Twig extend based on isxmlhttprequest - twig

I'm using Twig with Silex and are having some trouble with extend within an if statement. Basically the page is being extended even tho, the request is not done by AJAX.
{% if app.request.isXmlHttpRequest == false %}
{% extends 'layout.html.twig' %}
{% endif %}
However this works. The button is only being showed when the request is AJAX based.
{% if app.request.isXmlHttpRequest %}
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
{% endif %}
Also possibly worth mentioning my code is enclosed in an {% block content %} tag.
Does anyone have experience with this issue? (Being able to extend only if isXmlHttpRequest is false)
Thanks in advance

Try this one:
{% extends app.request.isxmlhttprequest ? "" : "layout.html.twig" %}
Behind the courtains extends is a token parsed in a way that no conditions can be placed around it, the outcome will be what you got: your template is always extended.
I'm not sure how it'll work with the empty string, you may need to create a "layout-ajax.html.twig" file with no content but the block you want to override.

Related

Digg-style pagination customize in template

I am using django-el-pagination package and trying to implement digg-style pagination on my home template. I am displaying it with..
{% get_pages %}
{{ pages.get_rendered }}
and it is showing like this <1234567> which is fine but
I want to add some css or class to change the way it look.
If you have any other way to achieve this. Please suggest..
please tell how can I customize it.
You can change it to make it looks something like this or like whatever you want:
Here is an example:
{% get_pages %}
<div class="pagination">
{% for page in pages %}
<li class="page-item">{{ page.number }}</li>
{% endfor %}
</div>
You can check the documentation here: https://django-el-pagination.readthedocs.io/en/latest/templatetags_reference.html#get-pages to check all the available options for get_pages

Twig Template Inheritance Issues

I'm trying to setup a clean structure for my Craft CMS install, but having issues with some very basic twig and a nice way to structure my things.
See this gist - why would my Navbar not show in this example?
Even better, I would like to structure my site like this - but it doesn't show anything? - another gist
Am I mixing the extend/block pattern the wrong way somehow? This feels so very basic and thus it's extremely frustrating. I would appreciate any help.
In your first gist, in index.twig, you extend base.twig correctly. However, you don't specify the contents of the navbar block, so the block defaults to the empty content that is set in base.twig.
You can change base.twig to include navbar.twig using the include function:
...
<div id="content">
{% include "navbar.twig" %}
{% block content %}{% endblock %}
</div>
...
You should also not extend base.twig in navbar.twig to prevent infinite recursion (base includes navbar, which extends base, which includes navbar, ...).
If you want the navbar to be overridable in index.twig and other files, you can retain the navbar block in base.twig and set its default contents to include navbar.twig:
...
<div id="content">
{% block content %}
{% include "navbar.twig" %}
{% endblock %}
{% block content %}{% endblock %}
</div>
...
Then, in index.twig, if you omit {% block navbar %}{% endblock %}, the navbar will use the contents from navbar.twig. Or you can also override the navbar block's contents:
{% extends "base" %}
{% block navbar %}
<h2>Overridden navbar</h2>
{% endblock %}
{% block content %}
<h2>Main content</h2>
{% endblock %}
In your second gist, in index.twig, you can change {% block head %}{% endblock %} to {% include "head.twig" %} and so on. In head.twig and other files, you should again not extend index.twig to prevent infinite recursions.
I recommend taking a look at Twig's documentation about the extends tag to see how blocks and templates actually work. In your two gists, blocks and templates are not used correctly.

Twig nesting multiple times

I am trying to work out the correct way to created a Twig component that has sections that are nested 3 deep.
I have a twig file that just creates a header with a class:
header.twig
<h2>{% block content %}{% endblock %}</h2>
and then a twig file that is mid level that consumes that header along with other low level twigs:
section.twig
<div class="section">
{% block header %}
{% embed "components/header.twig" %}
{% block content %}
{{ header }}
{% endblock %}
{% endembed %}
{% endblock %}
</div>
and then finally, page high level component that consumes the section twig:
page.twig
<div class="page">
{{ include("mid/section.twig", { header: fields.header }) }}
</div>
Now as you can see in the section.twig I'm able to override the block I create but in the highest level page.twig I can't override a block twice so I have to use an include instead of an embed.
To me this doesn't feel right and it feels very verbose. To clarify, I am using ACF so that's where fields.header comes from and yes I know that the header.twig can access that value directly but I am trying to create a structure in which the low and mid level components are "dumb" and the high level component controls the data.
For my given situation, am I going about this the best way that I can or is there another cleaner way that doesn't involve mixing embeds and includes?

conditionally define a block in twig 2

so heres the use case:
render a login form block in dynamic page structure, but only if user is not authenticated
block must not be defined if not authenticated (to preserve dynamic page structure)
twig 2.2
symfony 3.2
In a base template, I'm only rendering a block if its defined (not 'not emtpy')
base.html.twig
{% if block('left_sidebar') is defined %}
<div class="col-md-2">
{{- block('left_sidebar') -}}
</div>
<div class="col-md-10">
{% else %}
<div class="col-md-12">
{% endif %}
index.html.twig
For the above to work the block cant be defined at all (which is entirely designed). The following renders the block anyway, and I cant' figure out why.
{% if not is_granted('IS_FULLY_AUTHENTICATED') %}
{% block left_sidebar %}
{% include ':blocks:block__login.html.twig' %}
{% endblock %}
{% endif %}
I'm wondering if this is'nt working because of the same reason that the base template code does work. That is that the blocks are compiled before runtime, and the conditional statements are executed at runtime.
Can anyone please confirm that this I'm right? Or correct me if I'm wrong?
edit
I've tried forcing the result of the condition to both true and false, and the block is rendered in either case.
so, to wrap this up, as it seems to be a problem occurring in a few places, my suspicions are correct in that its a compile/runtime issue.
Blocks are compiled and because the if statement is at runtime one cant control the other.
heres the github issue thread if anyone wants more info.
The block() function appears to return a falsey value if nothing or only white space was output in it, so you can wrap the block in a truthiness test and in the child template make sure it is empty if you don't want it to show. Something like this worked for me:
base.html.twig:
{% if block('left_sidebar') %}
<div class="col-md-2">
{% block left_sidebar %}{% endblock %}
</div>
<div class="col-md-10">
{% else %}
<div class="col-md-12">
{% endif %}
index.html.twig
{% block left_sidebar %}
{% if not is_granted('IS_FULLY_AUTHENTICATED') %}
{% include ':blocks:block__login.html.twig' %}
{% endif %}
{% endblock %}
Twig compiles your templates into php classes, which you can see in the symfony cache directory, and blocks are methods in those classes. This means that blocks are always defined at compile time and conditionals like yours only determine if they are "executed".
For your use case, I would reccommend to to put the call to is_granted in the base template. Then you would not need to include any if element in index.html.twig because defining the sidebar block will have no effect if it is never used.
There is no real performance hit to defining unused blocks since the parsing of twig blocks only happens at compile time. Defining blocks whether or not are used is done, for instance, in symfony's own form component.

Javascript templating engine with twig embed-like functionality, does it exist?

I've been looking at javascript templating frameworks for the past day, but unless I missed something I can't seem to find a single one with the functionality I need.
What I need is what twig calls "embed". Basically it works like a regular template include (accept variables and return a blob of html), only with the possibility to define custom "blocks". A block is typically reserved for template inheritance (or "extend") though, and that's a bit limiting.
So far, Nunjucks came closest. It has import, include and extends functionality, but not embed. To clarify with a simple example:
Template (grid.html):
<div class="grid">
<div class="col1">
{% block col1 %}
[COL 1]
{% endblock %}
</div>
<div class="col2">
{% block col2 %}
[COL 2]
{% endblock %}
</div>
</div>
Template usage with embed in other template (twig syntax):
{% embed "grid.html" %}
{% block col1 %}
[whatever goes in col1, could be other embeds here ...]
{% endblock %}
{% block col2 %}
[whatever goes in col2, could be other embeds here ...]
{% endblock %}
{% endembed %}
Anyone know about a javascript templating framework that can do this? Maybe Nunjucks can and I missed it? Help would be greatly appreciated, because we're doing a node.js project and twig is simply not an option :)

Resources