I have been trying to figure out how to use the if not clause with Twig template engine.
According to the documents:
You can also use not to check for values that evaluate to false:
So I'm trying to use it like this:
{% if not signed_in %}
You are not signed in.
{% endif %}
And signed_in comes from a middleware. Looking like this:
if (!$this->container->auth->check()) {
/* Render a Sign-up */
return $this->container->view->render($response, 'subscriber/index.twig', ['signed_in' => false]);
}
So if I {{ dump(signed_in) }} when I'm not signed in it returns false. But when I'm signed in, singed_in returns null.
The current solution I'm going with is {% if signed_in is defined %}, but that is actually not what I'm looking for, or is it?
Twig != is a comparison operator.
The following comparison operators are supported in any expression: ==, !=, <, >, >=, and <=
You can use != to compare any two things that php lets you compare, and what you get back is a boolean.
Twig not is a logic operator. (so are and and or)
not: Negates a statement.
I recommend you to use:
{% if signed_in == true %} or {% if signed_in == false%}
This is the twig comportment:
{% set testTrue = true %}
{% set testFalse = false %}
{% set testNull = null %}
{% set testString = "something" %}
{% if testTrue %} {# true #}
{% if testFalse %}{# false#}
{% if testNull %} {# false#}
{% if testString %} {# true #}
{% if not testTrue %}{# false#}
{% if not testFalse %}{# true#}
{% if not testNull %} {# false !!!!!!!!!!!!!!!! #}
{% if not testString %} {# false#}
{% if testTrue == true %} {# true #}
{% if testFalse == true %} {# false#}
{% if testNull == true %} {# false#}
{% if testString == true %} {# true #}
{% if not testTrue == true %} {# false#}
{% if not testFalse == true %} {# true #}
{% if not testNull == true %} {# true #}
{% if not testString == true %} {# false#}
other tests good to know
{% if testTrue == 1 %} {# true #}
{% if testFalse == 1 %} {# false#}
{% if testTrue == "1" %} {# true #}
{% if testFalse == "1" %} {# false#}
Related
We have written us a script that allows us in Shopware 6 badges per categories. With many products crashes sometime after 5 minutes shopware crashes with the log message that the memory at php is not enough.
Have we done anything wrong here?
We have already packed the elements in an array (the graphics) and fetch them bundled from the server.
{# #var services \Shopware\Core\Framework\Script\ServiceStubs #}
{% set page = hook.page %}
{# #var page \Shopware\Storefront\Page\Product\ProductPage #}
{% set products = [] %}
{% if hook.page.cmsPage.type === 'product_list' %}
{% foreach hook.page.cmsPage.sections as section %}
{% foreach section.blocks as sectionBlock %}
{% if sectionBlock.type !== 'product-listing' %}
{% continue %}
{% endif %}
{% foreach sectionBlock.slots as slot %}
{% if slot.type !== 'product-listing' %}
{% continue %}
{% endif %}
{% foreach slot.data.listing.entities as product %}
{% set products = products|merge([product]) %}
{% endforeach %}
{% endforeach %}
{% endforeach %}
{% endforeach %}
{% endif %}
{% set categoryIds = products|reduce((carry, v) => carry|merge(v.categoryTree), []) %}
{% if categoryIds %}
{% set categories = services.repository.search('category', {'ids': categoryIds}) %}
{% set mediaIds = [] %}
{# Loop through all products and collect media ids #}
{% foreach products as product %}
{% set badgeList = [] %}
{% foreach categories.entities.getList(product.categoryTree) as category %}
{% if category.customFields.minds_cd_show_badge %}
{% set badgeList = badgeList|merge([{
'priority': category.customFields.minds_cd_badge_priority,
'mediaId': category.customFields.minds_cd_badge
}]) %}
{% endif %}
{% endforeach %}
{% set badge = (badgeList|sort((a, b) => a.priority <=> b.priority))|last %}
{% if badge %}
{% set mediaIds = mediaIds|merge([ badge.mediaId ]) %}
{% endif %}
{% endforeach %}
{# Get all badge media ids in a performant way #}
{% set mediaCollection = services.repository.search('media', {'ids': mediaIds}) %}
{# Loop through all products again and attach the badge #}
{% foreach products as product %}
{% set badgeList = [] %}
{% foreach categories.entities.getList(product.categoryTree) as category %}
{% if category.customFields.minds_cd_show_badge %}
{% set badgeList = badgeList|merge([{
'priority': category.customFields.minds_cd_badge_priority,
'mediaId': category.customFields.minds_cd_badge
}]) %}
{% endif %}
{% endforeach %}
{% set badge = (badgeList|sort((a, b) => a.priority <=> b.priority))|last %}
{% if badge %}
{% set badgeMedia = mediaCollection.get(badge.mediaId) %}
{% do product.addArrayExtension('mcb', {
'badge': badgeMedia
}) %}
{% endif %}
{% endforeach %}
{% endif %}
I think a real performance killer here might be that you potentially fetch a lot of categories. At least that could be the case if the category tree has many levels, with many categories on each level and products are assigned to multiple categories on different branches.
If I read this correctly you're really only interested in categories that have the custom field minds_cd_show_badge set to true. I assume those would potentially far less categories than the total number of entities you're fetching right now.
You could try setting a filter in your criteria targeting your custom field so you're only fetching the categories that are relevant in your case.
{% set criteria = {
'ids': categoryIds,
'filter': [
{ 'field': 'customFields.minds_cd_show_badge', 'type': 'equals', 'value': true }
]
} %}
{% set categories = services.repository.search('category', criteria) %}
Is there any way to check if form help exists directly in Twig template?
Pseudocode:
{% if formName.formField.help %}
{# ... #}
{% endif %}
You can use this:
{% if formName.formField.vars.help is not null %}
{# ... #}
{% endif %}
Another solution is just to use the filter default (if the value is not boolean though)
{% if formName.formField.vars.help|default %}
true
{% else %}
false
{% endif %}
demo
My code is:
{% for key, value in section.items %}
{% for key_t, value_t in title.items %}
{% if value_t.section_id == key|add:"0" %}
<li class="nav-item-header"><div class="text-uppercase font-size-xs line-height-xs">
{{value.title}}</div> <i class="icon-menu" title="Tables"></i></li>
{% endif %}
{% endfor %}
{% endfor %}
I want to break the for loop when if the condition is true. like as
{% for key, value in section.items %}
{% for key_t, value_t in title.items %}
{% if value_t.section_id == key|add:"0" %}
<li class="nav-item-header"><div class="text-uppercase font-size-xs line-height-xs">
{{value.title}}</div> <i class="icon-menu" title="Tables"></i></li>
{{break}}
{% endif %}
{% endfor %}
{% endfor %}
How is it possible? please help me...
There is no way to break out of a for loop in Django Template. However, you can achieve this by setting a variable and adding an if statement on the top like this.
{% set isBreak = False %}
{% for number in numbers %}
{% if 99 == number %}
{% set isBreak = true %}
{% endif %}
{% if isBreak %}
{# this is a comment. Do nothing. #}
{% else %}
<div>{{number}}</div>
{% endif %}
{% endfor %}
for some additional help check out this link
https://dev.to/anuragrana/for-loops-in-django-2jdi
or check this answer on stack overflow
How to break "for loop" in Django template
I'm trying to build a simple dropdown menu on drupal 8 by using twig templates. My problem is that I can't find a way to give the dropdown links a class. Here's my code
{#
/**
* #file
* Theme override to display a menu.
*/
#}
{% import _self as menus %}
{{ menus.menu_links(items, attributes, 0, menu_name) }} {# 1. #}
{% macro menu_links(items, attributes, menu_level, menu_name) %} {# 1. #}
{% import _self as menus %}
{# 1. #}
{%
set menu_classes = [
'c-menu-' ~ menu_name|clean_class,
]
%}
{% if items %}
{% if menu_level == 0 %}
<ul{{ attributes.addClass('navbar-nav u-header__navbar-nav') }}>
{% else %}
<ul class="hs-sub-menu list-unstyled u-header__sub-menu u-header__sub-menu-offset animated">
{% endif %}
{% for item in items %}
{%
set classes = [
menu_level ? 'dropdown-item u-header__sub-menu-list-item' : 'nav-item u-header__nav-item',
item.is_expanded ? 'menu-item',
item.is_collapsed ? 'menu-item',
item.in_active_trail ? 'active',
item.below ? 'nav-item hs-has-sub-menu u-header__nav-item hs-sub-menu-opened',
]
%}
<li{{ item.attributes.addClass(classes) }} data-event="hover" data-animation-in="fadeInUp" data-animation-out="fadeOut">
{%
set link_classes = [
not menu_level ? 'nav-link u-header__nav-link',
item.in_active_trail ? 'active',
item.below ? 'nav-link u-header__nav-link',
item.url.getOption('attributes').class ? item.url.getOption('attributes').class | join(' '),
]
%}
{% if item.below %}
{{ link(item.title, item.url, {'class': link_classes, 'data-toggle': 'dropdown', 'aria-expanded': 'false', 'aria-haspopup': 'true' }) }}
{{ menus.menu_links(item.below, attributes, menu_level + 1) }}
{% else %}
{{ link(item.title, item.url, {'class': link_classes}) }}
{% endif %}
</li>
{% endfor %}
</ul>
{% endif %}
{% endmacro %}
I just need to give a class to {{ menus.menu_links(item.below, attributes, menu_level + 1) }} completely independent from its parents.
Is there a way to achieve it? My output is like this
Sublink
I need to change it like this
Sublink
If there's any other way to do so like with custom module or with hooks, please let me know
Achieved the result with following code
{#
/**
* #file
* Theme override to display a menu.
*/
#}
{% import _self as menus %}
{{ menus.menu_links(items, attributes, 0, menu_name) }} {# 1. #}
{% macro menu_links(items, attributes, menu_level, menu_name) %} {# 1. #}
{% import _self as menus %}
{# 1. #}
{%
set menu_classes = [
'c-menu-' ~ menu_name|clean_class,
]
%}
{% if items %}
{% if menu_level == 0 %}
<ul{{ attributes.addClass('navbar-nav u-header__navbar-nav') }}>
{% else %}
<ul class="hs-sub-menu list-unstyled u-header__sub-menu u-header__sub-menu-offset animated">
{% endif %}
{% for item in items %}
{%
set classes = [
menu_level ? 'dropdown-item u-header__sub-menu-list-item' : 'nav-item u-header__nav-item',
item.is_expanded ? 'expanded',
item.is_collapsed ? 'collapsed',
item.in_active_trail ? 'active',
item.below ? 'nav-item u-header__nav-item expanded nav-item hs-has-sub-menu u-header__nav-item',
]
%}
<li{{ item.attributes.addClass(classes) }} data-event="hover" data-animation-in="fadeInUp" data-animation-out="fadeOut">
{%
set link_classes = [
'nav-link',
not menu_level ? 'u-header__nav-link' : 'u-header__sub-menu-nav-link',
item.in_active_trail ? 'active',
item.url.getOption('attributes').class ? item.url.getOption('attributes').class | join(' '),
]
%}
{% if item.below %}
{% set title %}
{{ item.title }}<span class="fa fa-angle-down u-header__nav-link-icon"></span>
{% endset %}
{{ link(title, item.url, {'class': link_classes, 'data-toggle': 'dropdown', 'aria-expanded': 'false', 'aria-haspopup': 'true' })}}
{{ menus.menu_links(item.below, attributes, menu_level + 1) }}
{% else %}
{{ link(item.title, item.url, {'class': link_classes}) }}
{% endif %}
</li>
{% endfor %}
</ul>
{% endif %}
{% endmacro %}
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.