Set Twig object property name using variable - object

I need to set an object property name dynamically in Twig:
{% set featureId = feature.id %}
{% set gridEnabled = gridEnabled|merge({featureId: true}) %}
But that sets "featureId" as a property of gridEnabled. Is there a way to tell Twig that featureId is a variable? I'm surprised it interprets that as a string without quotes.
Follow-up question: Here is the full set--I was able to further reduce to "feature.id". Can these lines be combined?
{% set gridEnabled = grid.enabled %}
{% set gridEnabled = gridEnabled|merge({(feature.id): true}) %}
{% set grid = grid|merge({'enabled':gridEnabled}) %}

Very easy actually,
{% set gridEnabled = gridEnabled|merge({(featureId): true}) %}
(edit) follow-up
{% set grid = grid | merge({'enabled' : (grid.enabled | merge({(featureId):1,}))}) %}

Related

Check if all elements in one array are contained by another | JS Array.every() equivalent

I'm looping over a collection of blog posts (Twig for loop) which appearance depends on tags given.
Here a quick example: I want to display all blog posts that have the tags "foo" and "bar".
It seems pretty easy to check if a post has one of the tags.
However it seems that checking if both tags are contained by a blog post isn't trivial.
What I want to accomplish is what the array.every() method in javascript does.
That's my current solution which works as expected but feels kinda fiddly and overcomplicated:
{% set given_tags_array = data.tags|split(',') %}
{% for post in posts %}
{% set post_categories_array = post.categories|map(category => category.name) %}
{% set bool_buffer_array = [] %}
{# push comparison result in bool array #}
{% for tag in given_tags_array %}
{% set bool_buffer_array = bool_buffer_array|merge([tag in post_categories_array]) %}
{% endfor %}
{# only display posts where all tags match #}
{% if false in bool_buffer_array %}
{% else %}
{# post data goes here #}
{% endif %}
{% endfor %}
As you can see inside the posts loop I'm checking if every given tag (i.e. "foo" and "bar") is part of the post categories array. I'm pushing the comparison result (boolean) to an empty array to check for any false values afterwards.
Why an array? I tried using a simple boolean variable but if any of the given tags is in the post categories array it resolves to true, which isn't exactly what I want.
So something like that doesn't work for me unfortunately:
{% for post in posts %}
{% set post_categories_array = post.categories|map(category => category.name)|sort|join('') %}
{% if given_tags_array|filter(given_tag => given_tag in post_categories_array) %}
{# post data goes here #}
{% endif %}
{% endfor %}
With this method I'm always doing an or comparison instead of an and comparison...
So...am I missing something and is there a simpler way to do that twig only?
Using the code you've already provided:
{% set temp = given_tags_array|filter(given_tag => given_tag in post_categories_array) %}
The filter filter returns a new array, this means temp should contain as many elements as your given_tags_array, if they are all inside the post_categories_array.
So if I'm not mistaken you could change your check to the following
{% for post in posts %}
{% set post_categories_array = post.categories|map(category => category.name)|sort|join('') %}
{% set temp = given_tags_array|filter(given_tag => given_tag in post_categories_array) %}
{% if temp|length == given_tags_array|length %}
{# display post #}
{% endif %}
{% endfor %}

Is there a limit on number of variables under Namespace definition in Jinja?

I am facing this problem of trying to customise the print format in Jinja. I tried to create a lot of variables using the namespace scoping, so that the variables can be used outside a loop.
For example, I tried the following code to insert as customised code in HTML to print format:
{% set det = namespace(abbr=’’) %}
{% set det = namespace(DATE=‘01-01-2021’) %}
{% set det = namespace(BA=0) %}
{% set det = namespace(BO=0) %}
{% set det = namespace(CO=0) %}
{% set det = namespace(CR=0) %}
{% set det = namespace(CRAW=0) %}
{% set det = namespace(PH=0) %}
{% set det = namespace(CE=0) %}
{% set det = namespace(CEAW=0) %}
{% set det = namespace(SL=0) %}
{% set det = namespace(RL=0) %}
{% set det = namespace(CPFE=0) %}
{% set det = namespace(CPFR=0) %}
{% set det = namespace(CPFT=0) %}
{% set det = namespace(TP=0) %}
{% set det = namespace(NS=0) %}
{% set det = namespace(count=0) %}
{% set det = namespace(TA=0) %}
{% set det.count = det.count + 1 %}
However, I get the following error:
self.environment.handle_exception()
File “env/lib/python3.8/site-packages/jinja2/environment.py”, line 925, in handle_exception
raise rewrite_traceback_stack(source=source)
File “”, line 23, in top-level template code
jinja2.exceptions.UndefinedError: ‘jinja2.utils.Namespace object’ has no attribute ‘count’
I am rather confused as det.count was defined as 0. I think it could be because I have created too many variables under the namespace that created this error.
How can I solve this?
This has nothing to do with a limit of the the number of variables in a namespace, you just keep on overriding your namespace by reassigning it.
This can be tested with a simpler example:
{% set ns = namespace(foo=0) %}
{% set ns = namespace(bar=42) %}
{% set ns.foo = ns.foo + 1 %}
Which yields the same message as yours:
'jinja2.utils.Namespace object' has no attribute 'foo'
If you want multiple variables defined in you namespace, pass them all, comma separated, to the definition of the namespace:
{% set ns = namespace(foo=0, bar=42) %}
{% set ns.foo = ns.foo + 1 %}

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

Twig: how to set object variable?

I try to create new variable from exists object variable in Twig template (filter is object):
{% for filter in filters %}
{% if filter.type != 'selectImage' %}
{{ filter.render()|raw }}
{% elseif filter.type == 'selectImage'%}
{% set selectFilter = filter %}
{% endif %}
{% endfor %}
but i get error:
Catchable fatal error: Object of class Filters\Filter could not be converted to string in vendor\twig\twig\lib\Twig\Environment.php(403) : eval()'d code on line 40
on
{% set selectFilter = filter %}
How i can set object to new vairable?
According to the official TWIG documentation, filter is the name of a tag in TWIG language.
You should rename your variable in your code to avoid problems in the generated PHP code:
{% set selectFilter = myFilter %}

Twig - Append string data to same variable

How would you append more data to the same variable in Twig? For example, this is what I'm trying to do in Twig:
var data = "foo";
data += 'bar';
I have figured out that ~ appends strings together in Twig. When I try {% set data ~ 'foo' %} I get an error in Twig.
The ~ operator does not perform assignment, which is the likely cause of the error.
Instead, you need to assign the appended string back to the variable:
{% set data = data ~ 'foo' %}
See also: How to combine two string in twig?
Displaying dynamically in twig
{% for Resp in test.TestRespuestasA %}
{% set name = "preg_A_" ~ Resp.id %}
{% set name_aux = "preg_A_comentario" ~ Resp.id %}
<li>{{ form_row(attribute(form, name)) }}</li>
{% endfor %}
You can also define a custom filter like Liquid's |append filter in your Twig instance which does the same thing.
$loader = new Twig_Loader_Filesystem('./path/to/views/dir');
$twig = new Twig_Environment($loader);
...
...
$twig->addFilter(new Twig_SimpleFilter('append', function($val, $append) {
return $val . $append;
}));
Resulting in the following markup:
{% set pants = 'I\'m wearing stretchy pants!' %}
{% set part2 = ' and they\'re friggin\' comfy!' %}
{% set pants = pants|append(part2) %}
{{ pants }}
{# result: I'm wearing stretchy pants! and they're friggin' comfy! #}
IMHO I find the above sample more intuitive than the ~ combinator, especially when working on a shared codebase where people new to the syntax might get a bit mixed up.

Resources