If statement with string length check - twig

I'm trying to check if a string is empty in a twig template but I don't understand this behaviour. I want to show a textarea element when the condition is met. Here's the code:
{% if item.payload.customizationText|length == 0 %}
<textarea class="customization-text">{{ item.payload.customizationText|trim }}</textarea>
{% endif %}
It always shows the textarea, whether the string has something in it or not. Am I missing something?
It's in shopware 6 by the way and the dump() fuction throws an error because it's undefined.
Also, this expression just outputs the string. Is the length expression not available?
{{ item.payload.customizationText|length }}

I believe there is a mistake in the question. It does not make sense to print the variable, only if it is empty.
If you want to show the text area in case the customizationText has some contents, you should use this:
{% if item.payload.customizationText|trim|length %}
<textarea class="customization-text">{{ item.payload.customizationText|trim }}</textarea>
{% endif %}
https://twigfiddle.com/nmk2kq/4

You can try it.
{% if item.payload.customizationText is defined and item.payload.customizationText is empty %}
<textarea class="customization-text">{{ item.payload.customizationText|trim }}</textarea>
{% endif %}

Related

Set a property value in an existing twig object

I would like to define a twig object that contains two properties :
The first one is a short text
The second one is a large text (so, i need to use {% set %}{% endset %} to keep readability of the template)
I first tried like this :
{% block principal %}
{% set a_form_help = {'help_toggle_label': 'See the big form field tip', 'help_content': ''} %}
{% set a_form_help.help_content %}>
<h1>This is rules for the field</h1>
<p>A looonng text that will be contained in a collapsed block</p>
<p>And several lines of tips for this field</p>
{% endset %}
{% endblock %}
But Twig complains about the use of the dot in the second {% set %} tag (for setting the large text content in the help_content property).
I've found this message (Twig - Why does it not allow us to set object / array values?) and then done this workaround by using a temporary variable:
{% block principal %}
{% set tmp_help_content %}>
<h1>This is rules for the field</h1>
<p>A looonng text that will be contained in a collapsed block</p>
{% endset %}
{% set a_form_help = {'help_toggle_label': 'See the big form field tip', 'help_content': tmp_help_content} %}
{{ dump(a_form_help) }}
{% endblock %}
I've used a a temporary variable since using the merge() filter would give the same result.
Is this workaroud a good practice or is there a better/cleaner way ?
Thanks in advance for any tip|advice ! :-)
There is no clean way to do it in twig.
Is this workaroud a good practice or is there a better/cleaner way ?
It is not a good practice. As twig is a templating language its responsability is only to display data, not to structure it. Your View Object should have been created elsewhere

How to evaluate twig expression

I've bend over backwards to solve this one, but no luck yet.
{% for field in fields %}
{{dump(form.children.~(field.label)~.vars.value)}}
{% endfor %}
U see the above code in twig? How do I get twig to evaluate (field.label) first and then evaluate the rest of the expression((form.children.Age.vars.value)). For now it throws the twig syntax error
Expected name or number.
Any ideas?
You can use:
{% for field in fields %}
{{ dump(form.children[field.label].vars.value) }}
{% endfor %}
Cheers

"Illegal offset type in isset or empty" when using a Twig macro

Using Grav v1.3.8 (running on PHP 5.6.30), I'm currently getting a Server error ("Illegal offset type in isset or empty") when trying to render a Twig template that is using a macro.
What's interesting is that this only happens when I use the macro by itself. As soon as I append a filter, like trim, everything works as expected.
The (shortened) macro file, helpers.twig:
{% macro ascii(str) %}
{% spaceless %}
{{ str|replace({
'Á': 'A',
'À': 'A',
'Â': 'A',
'Ã': 'A',
....
'ƒ': 'f'
})
}}
{% endspaceless %}
{% endmacro ascii %}
The template (MCVE):
{% import 'macros/helpers.twig' as helpers %}
{% set img = helpers.ascii('günter-berger.jpg') %}
{% if page.media[img] is defined %}
<img src="{{ page.media[img].url }}">
{% endif %}
This will produce the error. I narrowed it down to the if line. Apparently, the macro is working fine, but the condition will throw an error if fed the output of it, unfiltered. Adding any filter, like trim or lower, will get it to work again.
In other words, these work:
{% if page.media['günter-berger.jpg'] is defined %}
{% if page.media[helpers.ascii('günter-berger.jpg')|trim] is defined %}
But this will throw an error:
{% if page.media[helpers.ascii('günter-berger.jpg')] is defined %}
However, trying the same thing on twigfiddle, all three seem to work there.
Maybe an issue with Grav? Can someone point out any possible causes?
I forgot this, but a macro does not return a string but instead returns an instance of a Twig_Markup
{% set test = macro.ascii('Ghünter.jpg') %}
{{ dump(test) }}
Output : object(Twig_Markup)#10679 (2) { ["content":protected]=> string(11) "Ghunter.jpg" ["charset":protected]=> string(5) "UTF-8" }
Because the return type is an object you get this notification as you can't use objects as index. By using a filter on this instance, the magic method __toString method will be called, causing it to return a string, thus making it useable as index for an array
The only was to bypass this, would be writing a filter instead of a macro

Increment declared integer variable

I try to do zebra striping:
{% set counter = 0 %}
{% for entity in entities %}
<tr class="{{ cycle(['odd', 'even'], counter) }}">
{% counter++ %}
but I am getting error:
Unexpected tag name "counter" (expecting closing tag for the "for" tag
defined near line 11)
Could somebody give me solution?
[EDIT]
My bad solution is so easy:
{% set counter = counter + 1 %}
There's an easier way to do what you want:
{{ cycle(["even", "odd"], loop.index) }}
See the docs for the loop goodies.
If you want to have full control over the html, you can try this:
{% if loop.index is divisibleby(2) %}
...
{% endif %}
You can read it here: http://twig.sensiolabs.org/doc/tests/divisibleby.html
note that loop.index is used 'as-is', it does not refer to a variable rather the hidden indexing of the for loop.

How do you translate array items and join them?

Using twig, how can I translate all items in an array and join them with a slash?
Do I have to use an additional variable or is there a cleverer method?
For the moment, I'm doing something like this:
{% set labels = [] %}
{% for feature in menu_item.features %}
{% set labels = labels|merge([feature|trans([], 'features')]) %}
{% endfor %}
{{ labels | join(' / ')}}
It sucks.
Why not just output the content while you're looping ?
{% for feature in menu_item.features %}
{% if loop.index0 > 0 %}/{% endif %}
{{feature|trans}}
{% endfor %}
Maybe I'm late to the party, but you can now do this easily with the map filter:
{{ menu_item.features|map(feature => feature|trans)|join(' / ') }}
See documentation:
Twig >v1.41: https://twig.symfony.com/doc/1.x/filters/map.html
Twig >v2.10: https://twig.symfony.com/doc/2.x/filters/map.html
Twig v3.x: https://twig.symfony.com/doc/3.x/filters/map.html
Not everything should be done within the "view".
This type of code is probably much better placed within your controller logic and then passed into the view as the merged+joined result. Because in your example all you're doing is compiling a result which can much more easily be done within code.

Resources