TWIG REPLACE not Working - twig

I have the following twig code:
{% set button_class = button_class_off|default('toggle toggle-thumbs-down') %}
{% set button_toggle_swap = button_toggle_swap|default(['toggle-thumbs-down', 'toggle-thumbs-up']) %}
{% if value == '1' %}
{% dump(name) %}
{% for swap in button_toggle_swap %}
{% if swap in button_class %}
{% dump(swap) %}
{% dump(button_class) %}
{% set button_class = button_class|replace({swap: ""})|trim %}
{% dump(button_class) %}
{% else %}
{% set button_class = button_class ~ ' ' ~ swap %}
{% endif %}
{% endfor %}
{% endif %}
The dump shows:
"hifi"
"toggle-thumbs-down"
"toggle toggle-thumbs-down"
"toggle toggle-thumbs-down"
I have no idea why the replace does not work. I have tried this with and without the trim. The result is that the replace of swap with "" is ignored.
Any idea what I am doing wrong here?

OK. There appears to be some missing details in the documentation. If using a variable (not an absolute string) the the variable must be wrapped in parenthesis ().
This code works:
{% set button_class = button_class_off|default('toggle toggle-thumbs-down') %}
{% set button_toggle_swap = button_toggle_swap|default(['toggle-thumbs-down', 'toggle-thumbs-up']) %}
{% if value == '1' %}
{% for swap in button_toggle_swap %}
{% if swap in button_class %}
{% set button_class = button_class|replace({(swap): ""})|trim %}
{% else %}
{% set button_class = button_class ~ ' ' ~ swap %}
{% endif %}
{% endfor %}
{% endif %}
Thanks to this answer to str_replace in twig

Related

Opencart 3 TWIG: how to use AND operator

I'm trying to use the "AND" operator in TWIG in Opencart 3 and it doesn't work. Please tell me what I'm doing wrong.
I have some product attributes. And I want to make a condition that if two of the attribute with a specific ID are there, then the condition is met.
{% for attribute_group in attribute_groups %}
{% for attribute in attribute_group.attribute %}
{% if attribute.attribute_id == 2 and attribute.attribute_id == 3 %}
First condition
{% elseif attribute.attribute_id == 2 %}
Second condition
{% elseif attribute.attribute_id == 3 %}
Third condition
{% else %}
{% endif %}
{% endfor %}
{% endfor %
Here is text example:
if there is an attribute with ID equal 2 and an attribute with ID equal 3 then write "Floor/Number of floors".
if there is an attribute with ID equal 2 only then write "Floor"
if there is an attribute with ID equal 3 only then write "Numbers of floors".
Something can't be both X and Y at the same time. Furthermore this is something I'd advice you to test in the controller and not in the view.
Anyway if you wanted to do this in the view you will need to track of the found attributes. You could do this with two booleans or just add a counter.
{% set cnt = 0 %}
{% for attribute_group in attribute_groups %}
{% for attribute in attribute_group.attribute %}
{% if attribute.attribute_id == 2 or attribute.attribute_id == 3 %}
{% set cnt = cnt + 1 %}
{% endif %}
{% endfor %}
{% endfor %}
{% if cnt == 2 %}
{# do something #}
{% endif %}
You can simplify the if by using the test in
{% if attribute.attribute_id in [2, 3,] %}
Update of my answer because OP changed the requirements of the question
{% set words = [] %}
{% for attribute_group in attribute_groups %}
{% for attribute in attribute_group.attribute %}
{% if attribute.attribute_id == 2 %}
{% set words = words|merge(['Floor',]) %}
{% elseif attribute.attribute_id == 3 %}
{% set words = words|merge(['Numbers of floors',]) %}
{% endif %}
{% endfor %}
{% endfor %}
{% if words|default %}
{{ words|join('/') }}
{% endif %}
demo

Passing position values into Twig

I need to pass some values into my twig file. The defaults should be:
{% set pos.top|default(0) %}
{% set pos.right |default(0) %}
{% set pos.bottom |default(0) %}
{% set pos.left |default(0) %}
If no new values are given I don't need to use those, however, if either of the four is not 0 I need to add inline style
{% if ...(top == 2)... %}
style="position: relative; top: 2px"
{% endif %}
How do I put it together?
Something like this should work.
{% set addInline = false %}
{% for key, value in pos %}
{% if value != 0 %}
{% set addInline = true %}
{% endif %}
{% endfor %}
{% if addInline %}
style="
position: relative;
{% for key, value in pos %}
{% if value != 0 %}
{{ key }}: {{ value }}px;
{% endif %}
{% endfor %}
"
{% endif %}

How to add "Read More" in text displayed on several lines but only a certain number of lines with twig

I am using the following function in twig to show a part of the content of the description of a news item saved in a database:
{{ new.description|striptags|truncate(300,true)|raw|nl2br }}
With this function inside a p element in the html, I get the text whose characters do not exceed 300 and then I add "Read More" with an element a:
<p >{{ new.description|striptags|truncate(200,true)|raw|nl2br }}
<a class="href_blue" href="{{ path('new', {'id': new.id}) }}">
<strong> [Read More] </strong></a>
</p>
This code works for text that comes in a paragraph with more than 300 characters, but if for example I have another one with several "p" elements that are then changed in twig to elements and I need it to only show me several lines because I have A maximum elevation of the container where it is displayed, I would not know how to do it, since it shows me all line breaks until it does not exceed 300 characters.
To clarify it a little more, I show an image of the result:
What I need is that in the case of Title2 having many line breaks, just show some and add the "Read More" before so that the height of the div is equal to the previous one (to show the example I removed the max- Height and overflow: hidden).
How could I get that?
I greet your help in advance.
You could do something like this in Twig:
{% set paragraphs = new.description|split('</p>') %}
{% set summary = '' %}
{% for i in 1..10 %}
{% set summary = summary ~ paragraphs[i] %}
{% endfor %}
{% set summary = summary ~ '[Read More]' %}
Now you can use the summary variable in your twig file to show the truncated summary.
EDIT #2 based on comments
Then try this instead:
{% set paragraphs = new.description|split('</p>') %}
{% set summary = '' %}
{% for i in 1..(paragraphs|length) %}
{% set summary = summary ~ paragraphs[i] %}
{% if summary|length > 300 %}
{% set shortsummary = summary %}
{% endif %}
{% endfor %}
{% set final_summary = shortsummary|slice(:300) ~ '[Read More]' %}
EDIT #3 Code modified with the solution to the problem
{% set paragraphs = new.description|striptags|truncate(300,true)|raw|nl2br %}
{% set paragraphs = paragraphs|split('<br />') %}
{% set summary = "" %}
{% set cont = 90 %}
{% set type = "" %}
{% if paragraphs|length == 1 %}
{% set summary = paragraphs[0] %}
{% if summary|length <= 300 %}
{% set type = "" %}
{% else %}
{% set type = "anything" %}
{% endif %}
{% else %}
{% for i in 1..(paragraphs|length) %}
{% if summary|length + cont + paragraphs[i-1]|length <= 500 %}
{% set summary = summary ~ "<br>" ~ paragraphs[i-1] %}
{% set cont = cont + 90 %}
{% else %}
{% set type = "anything" %}
{% endif %}
{% endfor %}
{% endif %}
//In the case of a description with less than 300 characters the option "Read More" is not shown
{% if type != "" %}
<p>{{ summary|striptags|truncate(300,true)|raw|nl2br }}<a class="href_blue" href="{{ path('new', {'id': new.id}) }}"> <strong> [Read More] </strong></a></p>
{% else %}
<p>{{ summary|striptags|truncate(300,true)|raw|nl2br }}<a class="href_blue" href="{{ path('new', {'id': new.id}) }}"></a></p>
{% endif %}

Scope of variable in jinja2 template

I am writing jinja2 template based application. I am trying to write a logic to set variable.
{% set last_item = none %}
{% for u in users %}
{% if not u.username == user.username%}
{% if g.user.is_bestfriend(u) %}
{% set last_item = 'true' %}
{% endif %}
{% endif %}
{% endfor %}
{{last_item}}
but after {% endfor %}, last_item value is again set to none, instead of true. Is there any way to set it to true in jinja2 template?
Since version 2.10 you can do this using a namespace variable, set before entering the scope:
{% set ns = namespace(found=false) %}
{% for item in items %}
{% if item.check_something() %}
{% set ns.found = true %}
{% endif %}
* {{ item.title }}
{% endfor %}
Found item having something: {{ ns.found }}
See also the documentation: http://jinja.pocoo.org/docs/2.10/templates/#assignments
Due to scoping rules in jinja2, you cannot access a variable outside the scope that it was set in. Sorry :(

Testing current value of cycle

I want to render blocks of HTML in alternate orientations. Is this the correct syntax in order to get the current value of cycle?
{% if ( {{ cycle(['odd', 'even']) }} == 'odd' ) %}
foo
{% elseif %}
bar
{% endif %}
cycle(['odd', 'even']) should not be inside {{ }} in the if
statement
cycle() should have a second parameter given that counts the amount of loops
the {% elseif %} should either have a condition or be changed to {% else %}
This is what you should do to get the code to work as you want it to (loop 10 times):
{% for i in 0..9 %}
{% if cycle(['odd', 'even'], i) == 'odd' %}
foo
{% else %}
bar
{% endif %}
{% endfor %}
If you want the for to loop objects you can use loop.index (starts at 1) instead of i:
{% for object in objects %}
{% if cycle(['even', 'odd'], loop.index) == 'odd' %}
foo
{% else %}
bar
{% endif %}
{% endfor %}
or loop.index0 (starts at 0):
{% for object in objects %}
{% if cycle(['odd', 'even'], loop.index0) == 'odd' %}
foo
{% else %}
bar
{% endif %}
{% endfor %}

Resources