Closed matthbull closed 6 years ago
Think of a block as the equivalent of a method in a class. A block cannot be dynamic.
Interstingly though, if you look at the compiled output from twigfiddle, its resulted in this.
protected function doDisplay(array $context, array $blocks = array())
{
// line 3
$context["something"] = null;
// line 5
if ((($context["something"] ?? null) != null)) {
}
// line 1
$this->parent->display($context, array_merge($this->blocks, $blocks));
}
note that // line 1 has compiled outside of the line 5 if statement?
Ive also noticed that SonataAdminBundle uses the same syntax, so maybe theres a general lack of understanding in the community?
I think I will change Twig to throw an exception in such circumstances as it cannot work and people keep having this issue. The fact that it "fails" silently does not help. Any link to an example on SonataAdminBuindle?
Given that in the base template you don't make anything with the dynamic block, you can do the following:
main
block in base.html.twig
to hold the main contents of the page, including the optional left sidebar:{% block main %}
{% endif %}
left_sidebar
when needed:{% extends 'base.html.twig' %}
{% block main %}
...
{% set something = true %}
{% if not something %}
{% block left_sidebar %}
<h2>sidebar rendered</h2>
{% endblock %}
{% endif %}
{% endblock %}
But, if you don't really do anything with this left_sidebar
block in any other template ... you can remove it altogether:
{% extends 'base.html.twig' %}
{% block main %}
...
{% set something = true %}
{% if not something %}
<h2>sidebar rendered</h2>
...
{% endif %}
{% endblock %}
Finally, remember that newer Twig versions allow you to check for block existence:
{# does the block exist in this template? #}
{% if block('left_sidebar') is defined %} {{ block('left_sidebar')|raw }} {% endif %}
{# does the block exist in another template? #}
{% if block('left_sidebar', 'base.html.twig') is defined %} {{ block('left_sidebar', 'base.html.twig')|raw }} {% endif %}
oo thats an interesting idea Javiere, many thanks.
Fabian, heres the link to the sonata file. Its right at the bottom on line 353.
another thing that might be relevant.
If I move the conditional statement that defines the block into the base template, the rendered PHP is this:
// line 5
if ((($context["something"] ?? null) != null)) {
// line 6
echo " ";
$this->displayBlock('left_sidebar', $context, $blocks);
}
note the displayBlock call is in the right place. So this is only occurring in an extended template.
@matthbull this is because the child template is not displaying the block. It is overwriting a parent block, which will be displayed in the place where the parent wants to display it.
And blocks can never be defined conditionally ({% if %}
is a runtime conditional, while blocks are defined at compilation time)
thanks @stof, thats what I was thinking was the case, but it was really unclear as it was silently failing, as @fabpot had already mentioned.
Old but gold.
Had a similar need here. I wanned to show, by default, a base layout, but if user was not logged in, the login template should override the base template. Tried the same code that @matthbull, but didn't worked like a wanned.
Then, instead of extending the base layout in my index template, I've just included each template. Here's my before/after:
BEFORE (not working code)
{% extends "layout.twig" %}
{% if not var_loggedin and var_needlogin %}
{% block title %}My System Login{% endblock %}
{% block body %}
{{ include("login.twig") }}
{% endblock %}
{% endif %}
In the code above, the template always shown the login page, even if I was already logged in.
AFTER (now working OK ;D)
{% block page %}
{% if not loggedin and needlogin %}
{{ include("login.twig") }}
{% else %}
{{ include("layout.twig") }}
{% endif %}
{% endblock %}
Now, the login template is shown just if I'm not logged in and the page requires user to login, which is what I need.
Sorry for topic ressurrecting, but I'm new to template engines (about 3 days for now playing on Twig), and Google seems not that friendly as other subjects when the search is about Twig.
Hope this helps anyone else.
As this appears high in a search, if you need a dynamic block - instead of showing an empty block with no content, you could always use css to display:none
I came across the following scenario:
{% if block('my_block') is defined %}
<div class="some-extremely-obvious-css-inducing-class">
{{ block('my_block') }}
</div>
{% endif %}
With my extending template having
{% block my_block %}
{% if myConditional %}
foo
{% endif %}
{% endblock %}
So if my conditional fails we don't see foo
but we do see the extremely obvious surrounding div. To circumvent this me and my colleagues came up with the following solution:
{% if block('my_block') is defined and block('my_block') != '' %}
<div class="some-extremely-obvious-css-inducing-class">
{{ block('my_block') }}
</div>
{% endif %}
{%- block my_block -%}
{% if myConditional %}
foo
{% endif %}
{%- endblock -%}
We made the block spaceless by adding -
to the tags and we used that to check if the block is empty in the parent template.
Not a very clean solution but it's cleaner than anything else we could come up with.
I tried this out today and it appears to be working for me. I think my Twig version is 2.14.3
Using similar code to StijnVrolijk's example...
parent template
layout.twig
, partial, note the block('my_block')|trim != ''
{% if block('my_block') is defined and block('my_block')|trim != '' %}
<div class="some-extremely-obvious-css-inducing-class">
{{ block('my_block')|raw }}
</div>
{% endif %}
child template
{% extends "layout.twig" %}
{% block my_block %}
{% if myConditional %}
foo
{% endif %}
{% endblock %}
hi all,
twig 2.1
symfony3
Ive asked this on SO, but the only answer I have sort of confirms my suspicions, but I'd just like to check with you guys if this is actually the case.
I want to conditionally define a block in a twig template, as in the example below:
called template
base.html.twig
I have a use case where I dont actually want to define the block if its not needed (dynamic regions in the base template).
The problem is, the block always renders, regardless of a true/false result of the conditional check. But this only seems to happen if the template is extending another. Is this because of compile order? Or am I missing something.
Heres a fiddle to illustrate.
thanks in advance.
Matt