How to change value in this array - twig

{% set dataSrc = [{"campgroup0":"far", "total":3},{"campgroup0":"close", "total":4},{"campgroup0":"unknow", "total":8}] %}
I want to change total value of item 0 {"campgroup0":"far", "total":3}
I'm trying:
{% set item = {"campgroup0":"far", "total":0} %} {% set dataSrc = dataSrc|merge(item) %}
but just push another item

Related

Change value of array element at specific index

I want to change the value of array element at a specific position but whenever i am trying to so it throws me an error. Can anyone suggest me a way to change the value
{% set explode_field_id = data.field_id|split('-') %}
{% set explode_field_id_length = explode_field_id|length %}
{% set reqValue = explode_field_id_length - 1 %}
{% set explode_field_id[reqValue] = data.field_details[dependent_field] %}
{% set dependent_field_id = explode_field_id|join('-') %}
Here explode_field_id = categoryList-category_list-0-category_list
ERROR - Unexpected token "punctuation" of value "[" ("end of statement block" expected).

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 %}

Craft/Twig How to loop multiple key/value pairs and remove duplicates from that loop?

In Craft CMS, I have child entries where each child has a location with "city" and "country" values assigned to it.
I'm looking to output a list of "City, Country" text but remove any duplicates as two or more children might share the same "city,country" pair.
It's important that I can reference the city and country value for each child separately, because I need to use the country value for displaying a flag for each child item in the list.
I've learned about and tried my hand at "twig hash" and "associative arrays" and found usable snippets but can't make it work together for my case.
This does not work:
{% set children = entry.children %}
{% set locations = {} %}
{% for child in children %}
{% set city = child.location.parts.locality %}
{% set country = child.location.parts.country %}
{% if city not in locations %}
{% set locations = locations|merge({ city : country }) %}
{% endif %}
{% endfor %}
{% for location in locations %}
{% for k, v in location %}
{{ k }}, {{ v }} <br />
{% endfor %}
{% endfor %}
If you want to let the city be the key of your array you will need to wrap them in parantheses so the variable will get interpreted by twig.
Also you don't need the double for loop, you are building a one dimensional array
{% set locations = {} %}
{% for child in children %}
{% set city = child.city %}
{% set country = child.country %}
{% if city not in locations %}
{% set locations = locations|merge({ (city) : country }) %}
{% endif %}
{% endfor %}
{% for k,v in locations %}
{{ k }}, {{ v }} <br />
{% endfor %}
demo

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 %}

Counting the number of elements in array

I am looking to count the number of entries I have in an array in Twig. This is the code I've tried:
{%for nc in notcount%}
{{ nc|length }}
{%endfor%}
This however only produces the length of the string of one of the values in the array.
{{nc}} will produce an output of all the values of the array (there are 2) but I want the output to be just the number 2 (the count) and not all the information in the array.
Just use the length filter on the whole array. It works on more than just strings:
{{ notcount|length }}
This expands on the answer by Denis Bubnov.
I used this to find child values of array elements—namely if there was a anchor field in paragraphs on a Drupal 8 site to build a table of contents.
{% set count = 0 %}
{% for anchor in items %}
{% if anchor.content['#paragraph'].field_anchor_link.0.value %}
{% set count = count + 1 %}
{% endif %}
{% endfor %}
{% if count > 0 %}
--- build the toc here --
{% endif %}
Best practice of getting length is use length filter returns the number of items of a sequence or mapping, or the length of a string. For example: {{ notcount | length }}
But you can calculate count of elements in for loop. For example:
{% set count = 0 %}
{% for nc in notcount %}
{% set count = count + 1 %}
{% endfor %}
{{ count }}
This solution helps if you want to calculate count of elements by condition, for example you have a property name inside object and you want to calculate count of objects with not empty names:
{% set countNotEmpty = 0 %}
{% for nc in notcount if nc.name %}
{% set countNotEmpty = countNotEmpty + 1 %}
{% endfor %}
{{ countNotEmpty }}
Useful links:
length
set
for
{%for nc in notcount%}
{{ loop.index }}
{%endfor%}
loop.index -- The current iteration of the loop.
for reference:https://twig.symfony.com/doc/2.x/tags/for.html

Resources