how to remove line break in twig template containing a for loop and an include? - twig

I would like to remove a line break between multiple html tags (<a>) from a twig template which contains a for loop and an include of another twig template.
{% for child in field.value %}
{% include '#EasyAdmin/crud/field/association_link.html.twig' with {
field: {
value: child,},
} %}
{%- if loop.index < field.value|length -%}
,
{%- endif %}
{% endfor %}
And the twig templated included :
{% set url = ea_url()
.setController('App\\Controller\\Admin\\' ~ get_class(field.value)|split('\\')|last ~ 'CrudController')
.setEntityId(field.value.id)
.setAction('edit') %}
{% if url -%}
{{ field.value|markdown }}
{%- else -%}
{{ field.value|markdown }}
{%- endif -%}
It renders such a result :
<a href=url2>name1<a/>
,
<a href=url2>name2<a/>
How to get this result instead ?
<a href=url2>name1<a/>,
<a href=url2>name2<a/>
2nd row, 6th field : a break line before and after the comma

Related

Jinja2 template: output format

i am quite new to jinja2 template and i try to get output data by using jinja template.
data_list=
[
{
"v4-filter": {
"accept_1": [
{
"destination-prefix-list": "v4-future-prefix-list-1"
},
{
"source-prefix-list": "v4-future-prefix-list-2"
},
{
"source-prefix-list": "v4-future-prefix-list-3"
},
{
"destination-port": "80"
},
{
"destination-port": "443"
},
{
"action": "accept"
}
],
"accept_2": [
{
"destination-prefix-list": "v4-future-prefix-list4"
},
{
"source-prefix-list": "v4-future-prefix-list5"
},
{
"action": "accept"}]}}]
My jinja template
{%- for d in data_list -%}
{%- for k,v in d.items() -%}
{%- for term,value in v.items() -%}
term:: {{ term }}
{%- for dict_item in value -%}
{%- for key, value in dict_item.items() -%}
{% if key == "source-prefix-list" %}
source-address:: {{value}}
{% endif %}
{% if key == "destination-prefix-list" %}
destination-address:: {{value}}
{% endif %}
{% if key == "destination-port" %}
destination-port:: {{value}}
{% endif %}
{% if key == "action" %}
action:: {{value}}
{% endif %}
{%- endfor -%}
{%- endfor -%}
{%- endfor -%}
{%- endfor -%}
{%- endfor -%}
Output that i get
term:: accept_1
destination-address:: v4-future-prefix-list-1
source-address:: v4-future-prefix-list-2
source-address:: v4-future-prefix-list-3
destination-port:: 80
destination-port:: 443
action:: accept
term:: accept_2
destination-address:: v4-future-prefix-list4
source-address:: v4-future-prefix-list5
action:: accept
Output that i want
term accept_1 {
source-address:: v4-future-prefix-list-1
v4-future-prefix-list-2
v4-future-prefix-list-3
destination-port:: 80
443
action:: accept
}
term accept_2 {
source-address:: v4-future-prefix-list-5
destination-address:: v4-future-prefix-list-4
action:: accept
}
The jinja template looks not nice i know, but at the end it contains all the information that i need, is just question now to format properly as expected.
I tried by using nested if statement to properly reach the result but with no success.
Any hint is welcome.
Thanks, Pablo.
The following template will produce the requested output:
{%- for d in data_list -%}
{%- for k,v in d.items() -%}
{%- for term,value in v.items() -%}
{%- set label = namespace(source=false, dest=false, port=false) %}
term {{ term }} {
{%- for dict_item in value -%}
{%- for key, value in dict_item.items() -%}
{%- if key == "source-prefix-list" %}
{% if not label.source %}source-address::{% else %}{{ ' '*16 }}{% endif %} {{value}}
{%- set label.source = true %}
{%- endif %}
{%- if key == "destination-prefix-list" %}
{% if not label.dest %}destination-address::{% else %}{{ ' '*21 }}{% endif %} {{value}}
{%- set label.dest = true %}
{%- endif %}
{%- if key == "destination-port" %}
{% if not label.port %}destination-port::{% else %}{{ ' '*18 }}{% endif %} {{value}}
{%- set label.port = true %}
{%- endif %}
{%- if key == "action" %}
action:: {{value}}
{%- endif %}
{%- endfor %}
{%- endfor %}
}
{% endfor %}
{%- endfor %}
{%- endfor %}
Output:
term accept_1 {
destination-address:: v4-future-prefix-list-1
source-address:: v4-future-prefix-list-2
v4-future-prefix-list-3
destination-port:: 80
443
action:: accept
}
term accept_2 {
destination-address:: v4-future-prefix-list4
source-address:: v4-future-prefix-list5
action:: accept
}
Here we use a Jinja2 namespace object that we can use to track whether a label has been already printed or not in the current cycle. If a label is printed, we flip the boolean tracking variable in our label namespace variable and then just print enough space to correctly align the next printed value.

Iterating over Shopware Array and trying to get the key not working

Hey iam currently trying to get the description of the first menu navigation in Shopware 6.
For that i use the array page.header.navigation.active.breadcrumb and use its key in page.header.navigation.tree[key].description, but my key value is empty.
Thats happening due to the key beeing empty for no reason.
Heres my Code:
{% sw_extends "#Storefront/storefront/section/cms-section-sidebar.html.twig" %}
{% set topMenu = null %}
{% for key, value in page.header.navigation.active.breadcrumb %}
{% if loop.index == 2 %}
{% set topMenu = value %}
{# {% set topMenuDescription = page.header.navigation.tree[key].category.description %} #}
{% set topMenuDescription = key %}
{% endif %}
{% endfor %}
{% set currentMenu = page.header.navigation.active.breadcrumb | last %}
{# {% set currentMenu = page.header.navigation.active.name %} #}
{# {% set topMenuDescription = page.header.navigation.active.description %} #}
{# {% if ! topMenuDescription %}
{% set topMenuDescription = page.header.navigation.active.description %}
{% endif %} #}
{% block section_main_content_block %}
<div class="category-top">
<div class="category-banner">
<img src="/media/6a/fd/8b/1632946677/listing-banner.jpg">
<div class="category-banner-headlines">
{% if (currentMenu != topMenu) %}
<h3>{{ topMenu }}<h3>
<h2>{{ currentMenu }}<h2>
{% else %}
<h2 class="sameMenu">{{ currentMenu }}<h2>
{% endif %}
</div>
</div>
<div class="category-description">
<h1>{{ currentMenu }}</h1>
{{ topMenuDescription | trans | raw }}
</div>
</div>
{{ parent() }}
{% endblock %}
Also here is the structure of the key i want to get:
key-i-want-to-get
And heres the description i want to get:
description-i-want-to-get
Sidenote: The description in my example is empty, since i do the showcase in a seperate testing area, where i havent set a description
The reason topMenuDescription is empty is because the variable only exist inside the scope of the {% for %}-loop you've created. Outside this loop the variable doesn't exist.
In order to solve this issue you need to alter the scope of topMenuDescription by defining the variable outside the {% for %}-loop
{% set topMenuDescription = null %}
{% for key, value in page.header.navigation.active.breadcrumb %}
{% if loop.index == 2 %}
{% set topMenu = value %}
{# {% set topMenuDescription = page.header.navigation.tree[key].category.description %} #}
{% set topMenuDescription = key %}
{% endif %}
{% endfor %}
sidenote
You really should enable twig's debug whilst developing as your current snippet would throw a RuntimeError explaining the variable does not exist.

How to reduce duplication in Twig template

I have an if/else condition in a twig template which switches the out tag of a block of code, however the inner block is the same. Is there a way to reduce the duplication without creating a separate file?
This is what I have at the moment:
{% if condition %}
<a href="">
{{ content }}
</a>
{% else %}
<span>
{{ content }}
</span>
{% endif %}
I was hoping to do something such as:
{% if condition %}
<a href="">
{% include mycontent %}
</a>
{% else %}
<span>
{% include mycontent %}
</span>
{% endif %}
{% mycontent %}
{{ content }}
{% endmycontent %}
Is such a thing possible?
If you don't want to use extra files you could use macro's :
{% import _self as macro %}
{% macro foo(content) %}
{{ content }}
{% endmacro %}
{% for condition in [0, 1, 0, 1, ] %}
{% if condition %}
{{ macro.foo('Bar') }}
{% else %}
<span>{{ macro.foo('Bar') }}</span>
{% endif %}
{% endfor %}
fiddle
What you want to do has to be done using the normal syntax. an extra file. and include this file.
But if u want to do this without extra file. use the {% set variablecontent = "put content here" %} and then in your "{% mycontent %}" part u put {{ variablecontent }}
hope this helps

Passing Twig variables from array into an include

I have an array I'm iterating over to pull in different types of components into my page:
array(
'content'=> array(
'componentA'=>array(
'val'=>'1',
'title'=>'sample title'
),
'componentB'
)
)
I'm attempting to pass variables through from the array to the included template, but I'm not sure how to turn that string produced by the join into something that the include can understand as an array of variables. When I exclude the "with" from the first #components include, it prints out all the default values I've set in the iterable components like I would expect, but still gives me a white screen when I keep the with attribute in. When I display var itself, it returns this string:
(Note, I've also tried putting quotes around the {{k}} to no avail)
{ val:'1',title:'sample title' }
How can I pass the variables from my array to my component?
{% for key,item in content %}
{% if item is iterable %}
{% set var = [] %}
{% for k,v in item %}
{% set temp %}{% if loop.first %} { {% endif %}{{ k }}:'{{ v }}'{% if loop.last %} } {% endif %}{% endset %}
{% set var = var|merge([ temp ]) %}
{% endfor %}
{% set var = var|join(',') %}
{{ include ("#components/" ~ key ~ ".tmpl",var) }}
{% else %}
{{ include ("#components/" ~ item ~ ".tmpl") }}
{% endif %}
{% endfor %}
Your include statements are incorrect. You are using {{ include ... }}, which should be {% include ... %}.
The following snippet should work, if you only want to provide the data from the array (and not the loop data):
{% for key,item in content %}
{% if item is iterable %}
{% include ("#components/" ~ key ~ ".tmpl") with item %}
{% else %}
{% include ("#components/" ~ item ~ ".tmpl") %}
{% endif %}
{% endfor %}
You can then use {{ val }} and {{ title }} within your component template.
If you want to include the loop data, you can use:
{% for key,item in content %}
{% if item is iterable %}
{% include ("#components/" ~ key ~ ".tmpl") with {item: item, loop: loop} %}
{% else %}
{% include ("#components/" ~ item ~ ".tmpl") %}
{% endif %}
{% endfor %}
You can then use {{ item.val }}, {{ item.title }} and {{ loop.index }} in your component template.

Avoid the same statement in Twig template

I have
<div class="{{element.type == 'cover' ? 'cover-full' : 'fixed-width'}}">
<div class="element
{% if element.type == 'text' %}
element-text
{% elseif element.type =='image' %}
element-image
{% endif %}">
{% if element.type == 'text' %}
...
{% elseif element.type == 'image' %}
...
{% endif %}
</div>
As you can see I have to make the same if condition multiple times.
How can avoid to repeat every time the condition? I'm pretty new to Twig templating.
You will often have abit redundancy. But IMO it is a better practice to repeat HTML blocks instead of twig.
{% if element.type == 'text' %}
<div class="element element-text">
content
</div>
{% elseif element.type =='image' %}
<div class="element element-image">
content
</div>
{% else %}
{% include 'snippet.html' %}
{% endif %}
You have more valid and more readable HTML
If you change a condition you only have to change it one time
You could use {% include 'snippet.html' %} to reduce redundancy in HTML blocks
You can simplify your code:
{% if element.type in ['text','image'] %}element-{{element.type}}{% endif %}
You can use twig macro. On the top of that template add
{% macro element_class(type) -%}
{% if type in ['text','image'] %}element-{{type}}{% endif %}
{%- endmacro %}
{% from _self import element_class %}
And later:
<div class="{{element.type == 'cover' ? 'cover-full' : 'fixed-width'}}">
<div class="element {{ element_class(element.type) }}">
You can learn more about macros in Twig documentation.

Resources