Twig IF statement not working - twig

I am trying to use a simple if statement in Twig. However it doesn't seem to be working properly. The variable emailActivation is certainly being loaded into Twig properly as can be seen from the first line of the output in all cases.
However the if statement is behaving very oddly - for example it works as expected when the variable is false and being tested against 1 (case 2) but not when it is false and tested against 'false' (case 1).
Conversely when the variable is true the if statement works when the variable is tested against 'true' (case 3) but not when tested against 1 (case 4).
I only show the tests against 1 as a workaround I attempted, really I think the problem lies in (case 1). (case 5) and (case 4) suggest the numbers are being evaluated as boolean.
I also thought it could perhaps be an issue to do with caching, but to my knowledge I have set Twig up not to use a cache. Even if Twig is caching the problem still occurs on the first page load and when the browser is restarted. I have tried in IE and Firefox though again I don't think the browser is really relevant to the problem which lies in Twig itself as far as I can tell.
Thanks in advance for any assistance!
Case 1 emailActivation = false
Twig code
{{ emailActivation }}
{% if emailActivation == true %}
feature disabled
{% else %}
other content
{% endif %}
Output
false
feature disabled
Case 2 emailActivation = false
Twig code
{{ emailActivation }}
{% if emailActivation == 1 %}
feature disabled
{% else %}
other content
{% endif %}
Output
false
other content
Case 3 emailActivation = true
Twig code
{{ emailActivation }}
{% if emailActivation == true %}
feature disabled
{% else %}
other content
{% endif %}
Output
true
feature disabled
Case 4 emailActivation = true
Twig code
{{ emailActivation }}
{% if emailActivation == 1 %}
feature disabled
{% else %}
other content
{% endif %}
Output
true
other content
Case 5 emailActivation = true
Twig code
{{ emailActivation }}
{% if emailActivation == 0 %}
feature disabled
{% else %}
other content
{% endif %}
Output
true
feature disabled

One detail make think that emailActivation could be a string.
The output of {{ emailActivation }} is false or true, but I think that a boolean return something else (~ nothing or 1 ~).
The fact to test the condition as being a string should resolve the problem.
One way will be (for simply a string, not a big content):
{{ emailActivation }}
{{ (emailActivation == 'true') ? 'feature disabled' : 'other content' }}
Friendly

try same as it is equivalent to === in PHP
http://twig.sensiolabs.org/doc/tests/sameas.html

Related

Macro causing white space in Jinja2?

I was expecting that this macro
{% macro join_them(first) -%}
{% set data = [] %}
{% if first not in ["", None, "None"] %}
{{ data.append(first) }}
{% endif %}
{% for arg in varargs %}
{% if arg not in ["", None, "None"] %}
{{ data.append(arg) }}
{% endif %}
{% endfor %}
{{' '.join(data)}}
{%- endmacro %}
Would render this
<td> * {{ join_them(docs["Author"]["Name"].title, docs["Author"]["Name"].first, docs["Author"]["Name"].middle, docs["Author"]["Name"].last, docs["Author"]["Name"].suffix) }}</td>
As this line, without the use of the macro, does
<td> * {{ ' '.join([docs["Author"]["Name"].title, docs["Author"]["Name"].first, docs["Author"]["Name"].middle, docs["Author"]["Name"].last, docs["Author"]["Name"].suffix])}}</td>
The non macro version is working fine, and outputing the name information correctly, but the Macro version is putting out white space and some "None" strings.
e.g.
<td> *
None
None
Computer Community
*</td>
<td>Computer Community </td>
Anyone have any suggestions on what I'm missing here? Or a better way to handle this? I don't typically use macros in Jinja2, but this seemed a perfect opportunity to do so.
The macro is indeed causing those blank lines, and you had the right approach already, you need to use whitespace control to remove them. You only placed them at the beginning and the end of your macro but note that:
You can also strip whitespace in templates by hand. If you add a minus sign (-) to the start or end of a block, a comment, or a variable expression, the whitespaces before or after that block will be removed
Source: https://jinja.palletsprojects.com/en/3.1.x/templates/#whitespace-control, emphasis, mine
So, for each and every single block in your macro, you have to repeat this operation. To be extra sure, what you could do here is to frame any block in the macro with the minus sign.
Then for the None appearing, this is because you are using an expression delimiter {{ ... }} to append to your array, when you should use a statement delimiter {% ... %} and a do, as pointed in the documentation
If the expression-statement extension is loaded, a tag called do is available that works exactly like the regular variable expression ({{ ... }}); except it doesn’t print anything. This can be used to modify lists
{% do navigation.append('a string') %}
Source: https://jinja.palletsprojects.com/en/3.1.x/templates/#expression-statement
So, your macro should end up looking like:
{%- macro join_them() -%}
{%- set data = [] -%}
{%- for arg in varargs if arg not in ["", None, "None"] -%}
{%- do data.append(arg) -%}
{%- endfor -%}
{{- ' '.join(data) -}}
{%- endmacro -%}
Note that, if you don't have the expression-statement extension loaded, you could also replace the {% do ... %} blocks by this inline-if 'hack':
{{- '' if data.append(arg) -}}

Displaying a link in a Twig temple

It seems easy, but I encounter a weird behavior.
In a twig file :
{% set my_html = 'Hello world' %}
{{- true is not same as(false) ? (true is same as(false) ? ('1'~my_html)|raw : ('2'~my_html)|raw) -}}
The printed part is ('2'~my_html)|raw and it works fine : I see a real link.
Output is :
2Hello world
Now, it works only because I apply the raw filter to ('1'~my_html)... Try this :
{% set my_html = 'Hello world' %}
{{- true is not same as(false) ? (true is same as(false) ? ('1'~my_html) : ('2'~my_html)|raw) -}}
And it will display : 2Hello world
I don't understand why I need to apply a filter on something else to get the expected result ? Is it a bug ?
This is a documented behavior of the raw filter. I quote the note from that page:
Be careful when using the raw filter inside expressions:
{% autoescape %}
{% set hello = '<strong>Hello</strong>' %}
{% set hola = '<strong>Hola</strong>' %}
{{ false ? '<strong>Hola</strong>' : hello|raw }}
does not render the same as
{{ false ? hola : hello|raw }}
but renders the same as
{{ (false ? hola : hello)|raw }} {% endautoescape %}
The first ternary statement is not escaped: hello is marked as being
safe and Twig does not escape static values (see escape). In the
second ternary statement, even if hello is marked as safe, hola
remains unsafe and so is the whole expression. The third ternary
statement is marked as safe and the result is not escaped.
And a comment on a github issue clarifies that the concatenation operator marks your string as unsafe. So in your case
{% set my_html = '<' %}
{# ('1'~my_html) is not safe, so the whole expression is not #}
{{ false
? ('1'~my_html)
: ('2'~my_html)|raw
}}
includes two strings: a safe one, ('2'~my_html)|raw) and an unsafe one, ('1'~my_html) (because it does not apply the raw filter), so as the note from raw documentation says, the whole expression stays unsafe and autoescaping is applied. But in the other case when both strings are marked safe, the whole expression becomes safe and the autoesaping is not applied:
{% set my_html = '<' %}
{# now both strings are safe, so is the whole expression #}
{{ false
? ('1'~my_html)|raw
: ('2'~my_html)|raw
}}
This is not a bug but, due to the fact the default settings of twig will autoescape variables.
You can read more about it in the documentation.

How to unset a variable in Twig

So I'm working with conditional rendering in a component reused at multiple place.
I have a twig variable my_var set as 'something'.
I want to unset it in my template.
Something like {% unset my_var %} the way this condition {% if not my_var %} would be fullfill.
I've tried to set it to false or null but this is not working anytips ?
Working here:
{% set my_var = false %}
{% if not my_var %}
not true
{% else %}
true
{% endif %}
twigfiddle

Find needle within haystack in twig

I want to check whether a certain word exists in a string. However, there's not other operator that exists which can do the job except containment operator. The following doesn't work to my utter frustration.
{% set deduction = 'Less Withholding Tax Thereon' %}
{% if 'Witholding' in deduction %}
{% set test = "with" %}
{% else %}
{% set test = "out" %}
{% endif %}
{{ test }}
Please see fiddle with various tests all amounting to same result
https://twigfiddle.com/00odoi

How to use Twig_Markup object type in an If statement

I want to reuse pretty heavy logic only code a few times, in php I would use a function, but in twig I went with a solution from this old question.
In short, I use a macro like that:
{% import _self as test %}
{% macro check() %}
{{ test }}
{% endmacro %}
{% set v = test.check() %}
{% if v == 'test' %}
this should display
{% endif %}
Here is a fiddle: https://twigfiddle.com/kyv3zr/2
The problem is that v is a Twig_markup object. It doesn't seem to have any public properties. Running dump on it gives me this:
object(Twig_Markup)#1244 (2) { ["content":protected]=> string(13) " 1 " ["charset":protected]=> string(5) "UTF-8" }
How do I use it in an if statement?
Or is there a better way of storing a logic only code for reuse across templates?
If the object is called v then the dump seems to show it has a content value, so try:
{% if v.content == '1' %}
{# do something here #}
{% endif %}
not certain though, but try it.
EDIT #2 - based on comments question.
So I guess if you want to use v in an if statement, you would use it like so:
{% if v == '1' %}
{# do something here #}
{% endif %}
This presumes it does equal to "1".

Resources