How to render HTML to a variable - twig

I need to render a list of HTML elements with content and put it into a variable. How can I do this efficient in twig?
e.g. I need to render the post tracking URLs from an order which can have several shippings / parcels.
{% for delivery in order.deliveries %}
{% for trackingCode in delivery.getTrackingCodes() %}
{{ trackingCode }}<br/>
{% endfor %}
{% endfor %}
Instead of printing this directly into the output I like first to put this rendered output into a variable like
{% set output = ... %}
...
{{ output }}
How can I do this in twig?

Just the concatenate the html to the output variable. Keep in mind you'll need to define to the variable outside the for-loop in order to use it outside the loop.
{% set foo = '' %}
{% for i in 1..10 %}
{% set foo = foo ~ ''~i~'' %}
{% endfor %}
{{ foo|raw }}
demo

After long search I found a better more efficient way
you can use {% set var %} with {% endset %} as a whole output block. Means the whole output will be set to the variable. This makes the life much easier and readable.
e.g.
{% set trackingText %}
{% for delivery in order.deliveries %}
{% for trackingCode in delivery.getTrackingCodes() %}
{{ trackingCode }}<br/>
{% endfor %}
{% endfor %}
{% endset %}
...
{% if trackingText|trim is not empty %}
You can track the delivery by using the following URL:<br/>
{{ trackingText }}
<br/>
{% endif %}

Related

Twig strip textarea and create array

I'm trying to strip some text from a value and afterwards create an array from it with the stripped values.
I'm having troubles to strip the text value.
I can only do this on the frontend since I have no access to the backend (SaaS platform)
In below example value.value (originally a textarea) returns the following text:
[185047078]1x something - Type 1
[415533322]1x something - something
[152890667]1x something 500x500 mm
I want to strip the text so I have [185047078], [415533322], [152890667] left or without the brackets.
Normally in JS you would do something like:
hide_ids = txt.match(/[^\]\[]+(?=\])/g)
However it need to be done in Twig.
Afterwards I want to push the values into an array hide_ids.
{% set hide_ids = [] %}
{% if product.custom %}
{% for custom in product.custom %}
{% if 'Some title' in custom.title %}
{% for value in custom.values %}
{% set hide_this_id = value.value %}
{% if hide_this_id matches '{/[^\]\[]+(?=\])/g}' %}
{% set hide_ids = hide_ids | merge([hide_this_id]) %}
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}
{% endif %}
{% set hidden = false %}
{% if id in hide_ids %}
{% set hidden = true %}
{% endif %}
What is the equivalent of match in Twig? I also tried replace but I just can't get that text stripped.
Any help greatly appreciated!
You could go with some simple string functions.
{% for id in ids %}
{{ id | split(']', 2)[0] | replace({'[': '',}) }}
{% endfor %}
demo
split is the explode of twig. This will separate your string in chased based on the ] character. The 2nd parameter (2) ensures there will only be maximum 2 parts in the array.
replace is just str_replace
If you wanted to solve this with regex you would either need to write a function/filter with preg_match or install an extension like this

Use loop.index as part of template name to include with Twig?

I have an array of 3 items so in the following I'm including sub-component.twig 3 times:
{% for i in array %}
<div class="my-class">
{% include "sub-component.twig" %}
</div>
{% endfor %}
However I actually have 3 slightly different templates and I would like to load a different one for each iteration over the array:
sub-component-1.twig
sub-component-2.twig
sub-component-3.twig
When I print loop.index in the template the result is "1", "2" and "3". Can I therefore use the index to form the template name?
{% for i in array %}
<div class="my-class">
{{ loop.index }}
{% include ["sub-component-" ~ loop.index ~ ".twig"] %}
</div>
Possibly because I'm using gulp twig I had to break things out into variables for this to work.
https://github.com/zimmen/gulp-twig
{% for i in array %}
<div class="my-class">
{% set sub-component_1 = "sub-component-" %}
{% set sub-component_2 = loop.index %}
{% set sub-component_3 = ".twig" %}
{% set sub-component_full = sub-component_1 ~ sub-component_2 ~ sub-component_3 %}
{% include sub-component_full %}
</div>
{% endfor %}

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 :(

for loop counter with Twig or Swig

Anyone know of a clean way to do this in Twig/Swig:
{% for(i = 0; i < 100; i++) %}
blah....
{% endfor %}
If you have a number, then you can just convert this to an array and then use Swig's standard for tag. This is simplest if you always want to 'start' the loop from 0 though.
For example:
{% set productCount = 6 %}
{% set productCountAsArray = Array(productCount) %}
{# This will run productCount times #}
{% for x, y in productCountAsArray %}
This is for number: {{ x }}
{% endfor %}
The swig docs have since (ivoba's answer) been updated and now contain special loop variables, which include loop.index:
{% for x in y %}
{% if loop.first %}<ul>{% endif %}
<li>{{ loop.index }} - {{ loop.key }}: {{ x }}</li>
{% if loop.last %}</ul>{% endif %}
{% endfor %}
http://paularmstrong.github.io/swig/docs/#tags-for
For twig its:
{% for i in 0..100 %}
* {{ i }}
{% endfor %}
From http://twig.sensiolabs.org/doc/tags/for.html
For swig the docs dont mention it yet:
https://github.com/paularmstrong/swig/blob/master/docs/tags.md#for
i cant really tell but it might be not supported in swig since its django inspired and django also seems to lack this feature nativly: https://code.djangoproject.com/ticket/5172
so i would like to pass the swig part to the next one.

Twig: in_array or similar possible within if statement?

I am using Twig as templating engine and I am really loving it. However, now I have run in a situation which definitely mustbe accomplishable in a simpler way than I have found.
What I have right now is this:
{% for myVar in someArray %}
{% set found = 0 %}
{% for id, data in someOtherArray %}
{% if id == myVar %}
{{ myVar }} exists within someOtherArray.
{% set found = 1 %}
{% endif %}
{% endfor %}
{% if found == 0 %}
{{ myVar }} doesn't exist within someOtherArray.
{% endif %}
{% endfor %}
What I am looking for is something more like this:
{% for myVar in someArray %}
{% if myVar is in_array(array_keys(someOtherArray)) %}
{{ myVar }} exists within someOtherArray.
{% else %}
{{ myVar }} doesn't exist within someOtherArray.
{% endif %}
{% endfor %}
Is there a way to accomplish this which I haven't seen yet?
If I need to create my own extension, how can I access myVar within the test function?
Thanks for your help!
You just have to change the second line of your second code-block from
{% if myVar is in_array(array_keys(someOtherArray)) %}
to
{% if myVar in someOtherArray|keys %}
in is the containment-operator and keys a filter that returns an arrays keys.
Just to clear some things up here. The answer that was accepted does not do the same as PHP in_array.
To do the same as PHP in_array use following expression:
{% if myVar in myArray %}
If you want to negate this you should use this:
{% if myVar not in myArray %}
Try this
{% if var in ['foo', 'bar', 'beer'] %}
...
{% endif %}
another example following #jake stayman:
{% for key, item in row.divs %}
{% if (key not in [1,2,9]) %} // eliminate element 1,2,9
<li>{{ item }}</li>
{% endif %}
{% endfor %}
Though The above answers are right, I found something more user-friendly approach while using ternary operator.
{{ attachment in item['Attachments'][0] ? 'y' : 'n' }}
If someone need to work through foreach then,
{% for attachment in attachments %}
{{ attachment in item['Attachments'][0] ? 'y' : 'n' }}
{% endfor %}
It should help you.
{% for user in users if user.active and user.id not 1 %}
{{ user.name }}
{% endfor %}
More info: http://twig.sensiolabs.org/doc/tags/for.html
Here's one to complete the answers with all the possibilities of Twig these days:
To achieve something like this:
{% for myVar in someArray %}
{% if myVar in someOtherArray|keys %}
{{ myVar }} exists within someOtherArray.
{% else %}
{{ myVar }} doesn't exist within someOtherArray.
{% endif %}
{% endfor %}
(https://twigfiddle.com/0b5crp)
You could also use array mapping and have the following one-liner:
(Twig >= 1.41 or >= 2.10 or any 3.x version)
{{ someArray|map(myVar => myVar ~ (myVar not in someOtherArray|keys ? ' doesn\'t') ~ ' exists within someOtherArray.')|join('\n') }}
Which outputs something quite similar.
Also see this Twig fiddle: https://twigfiddle.com/dlxj9g
{% if myVar in myArray %} without keys helps me

Resources