Drupal 8 How can I give dropdown links a class? - twig

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

Related

Macro to automatically generate section numbers

I am struggling with creating a macro to automatically generate section number and subsection numbers. I had thought the snippet below would work but it is failing to assign the value if not already set. I am sure this is obvious but my lack of jinja experience is showing... or perhaps lack of Python experience... or both!
I get this error.
{% set sectionnumber.value = sectionnumber.value + 1 %}
jinja2.exceptions.TemplateRuntimeError: cannot assign attribute on non-namespace object
{% macro getsectionnumber(type) -%}
{% if subsectionnumber is none %}
{% if sectionnumber is none %}
{% set sectionnumber = namespace(value=0) %}
{% endif %}
{% set subsectionnumber = namespace(value=0) %}
{% endif %}
{% if type == 'section' %}
{% if sectionnumber is none %}
{% set sectionnumber = namespace(value=0) %}
{% endif %}
{% set sectionnumber.value = sectionnumber.value + 1 %}
{{ sectionnumber.value }}
{% endif %}
{% if type == 'subsection' %}
{% set subsectionnumber.value = subsectionnumber.value + 1 %}
{{ sectionnumber.value }}.{{ subsectionnumber.value }}
{% endif %}
my template:
template = """
{% set sectionnumber = namespace(value=0) %}
{% set subsectionnumber = namespace(value=0) %}
{% macro getsectionnumber(type) -%}
{% if type == 'section' %}
{% set sectionnumber.value = sectionnumber.value + 1 %}
{{ sectionnumber.value }}
{% endif %}
{% if type == 'subsection' %}
{% set subsectionnumber.value = subsectionnumber.value + 1 %}
{{ sectionnumber.value }}.{{ subsectionnumber.value }}
{% endif %}
{% endmacro %}
{{ getsectionnumber('section') }}
{{ getsectionnumber('subsection') }}
{{ getsectionnumber('subsection') }}
{{ getsectionnumber('section') }}
{{ getsectionnumber('subsection') }}
{{ getsectionnumber('subsection') }}
"""
print the template:
print(Template(template).render())
result:
1
1.1
1.2
2
2.3
2.4

twig attrbutes.addclass nesting issue

Apologies if this has been asked before, but I'm on my first week working with Drupal and Twig.
I have the following code:
{%
set container_classes = [
'paragraph',
'paragraph--type--' ~ paragraph.bundle|clean_class,
view_mode ? 'paragraph--view-mode--' ~ view_mode|clean_class,
not paragraph.isPublished() ? 'paragraph--unpublished',
'container'
]
%}
{% set image_classes = [
'col-12'
]
%}
{% block paragraph %}
{% block content %}
<div{{ attributes.addClass(container_classes) }}>
<div class='row'>
<div{{ attributes.addClass(image_classes) }} data-type='image'>
{{ content.field_two_column_image }}
</div>
<div class='col-12 col-lg-auto' data-type='copy'>
{{ content.field_two_column_copy }}
</div>
</div?>
</div>
{% endblock %}
{% endblock paragraph %}
My issue is the nested attributes.addClass. When I look at the HTML, I'm also seeing the container_classes classes, which is not what I'm looking for.
So how can I separate the two?
You can Create Attributes in Twig.
Something like this should work.
{# attributes for container #}
{% set container_attributes = create_attribute() %}
{%
set container_classes = [
'paragraph',
'paragraph--type--' ~ paragraph.bundle|clean_class,
view_mode ? 'paragraph--view-mode--' ~ view_mode|clean_class,
not paragraph.isPublished() ? 'paragraph--unpublished',
'container'
]
%}
{% set container_attributes = container_attributes.addClass(container_classes) %}
{# attributes for image #}
{% set image_attributes = create_attribute() %}
{% set image_classes = [
'col-12'
]
%}
{% set image_attributes = image_attributes.addClass(image_classes) %}
{% block paragraph %}
{% block content %}
<div{{ container_attributes }}>
<div class='row'>
<div{{ image_attributes }} data-type='image'>
{{ content.field_two_column_image }}
</div>
<div class='col-12 col-lg-auto' data-type='copy'>
{{ content.field_two_column_copy }}
</div>
</div?>
</div>
{% endblock %}
{% endblock paragraph %}

Conditionnal display with twig

I'm using Twig in Views to rewrite output with condition.
{{ field_illus_lycee }}
{% if field_titre_pour_views is defined %}
{% if field_titre_pour_views is not empty %}
{{ field_titre_pour_views }}
{% endif %}
{% else %}
{{ title }}
{% endif %}
<span class="accroche-admin">{{ body }}</span>
I want to display field_titre_pour_views only if it exists and isn't empty, otherwise the regular title should be displayed. But at this point the regular title isn't displayed.Inspired by this
I don't understand which mistake I've made.
EDIT: correct code
{{ field_illus_lycee }}
{% if field_titre_pour_views is defined %}
{% if field_titre_pour_views is not empty %}
{{ field_titre_pour_views }}
{% else %}
{{ title }}
{% endif %}
{% else %}
{{ title }}
{% endif %}
<span class="accroche-admin">{{ body }}</span>
Sometimes, to ask is to find...this code do the trick:
{% if field_titre_pour_views |default %}
{{ field_titre_pour_views }}
{% else %}
{{ title }}
{% endif %}
Auto fixed :)
Hope it would help someone else.

Accessing associative array in twig

I have this array:
$modules = array(
'users',
'submodule' => array(
'submodule1',
'submodule2',
),
);
My question is how can I access all the values and display it on html?
I have tried the following but no luck :
{% for key, module in modules %}
{% if modules.key is iterable %}
{{ module }}
{$ else %}
{{ module }}
{% endif %}
{% endfor %}
Thanks!
If your array has only 2 levels, you can just do something close to what you did:
{% for module in modules %}
{% if module is iterable %}
{% for submodule in module %}
<p>{{ submodule }}</p>
{% endfor %}
{% else %}
<p>{{ module }}</p>
{% endif %}
{% endfor %}
Will give you (with the context you given):
<p>users</p>
<p>submodule1</p>
<p>submodule2</p>
See fiddle
But if your array has an arbitrary number of levels, you should do some recursive using macros:
{% macro show_array(array) %}
{% from _self import show_array %}
{% for module in array %}
{% if module is iterable %}
{{ show_array(module) }}
{% else %}
<p>{{ module }}</p>
{% endif %}
{% endfor %}
{% endmacro %}
{% from _self import show_array %}
{{ show_array(modules) }}
With the following context (in YAML format):
modules:
0: users
submodule:
0: submodule1
1: submodule2
subsubmodule:
0: subsubmodule1
1: subsubmodule2
This will give you:
<p>users</p>
<p>submodule1</p>
<p>submodule2</p>
<p>subsubmodule1</p>
<p>subsubmodule2</p>
See fiddle

Navigation link works on mobile but not on desktop

i have this website http://sds-test.nowcommu.myhostpoint.ch/de (please use the "de" at the end) and the last link of the navigation "RECHENZENTRUM" does not works on desktop but works on mobile. How can i solve it? This is the twig code:
{% extends 'partials/base.html.twig' %}
{% set show_onpage_menu = header.onpage_menu == true or header.onpage_menu is null %}
{% macro pageLinkName(text) %}{{ text|lower|replace({' ':'_'}) }}{% endmacro %}
{% block javascripts %}
{% if show_onpage_menu %}
{% do assets.add('theme://js/singlePageNav.min.js') %}
{% endif %}
{{ parent() }}
{% endblock %}
{% block bottom %}
{{ parent() }}
{% if show_onpage_menu %}
<script>
// singlePageNav initialization & configuration
$('#navbar').singlePageNav({
offset: $('#header').outerHeight(),
filter: ':not(.external)',
updateHash: true,
currentClass: 'active'
});
</script>
{% endif %}
{% endblock %}
{% block header_navigation %}
{% if show_onpage_menu %}
<ul class="navigation">
{% for module in page.collection() %}
{% set current_module = (module.active or module.activeChild) ? 'active' : '' %}
<li class="{{ current_module }}">{{ module.menu }}</li>
{% endfor %}
{% set datacenter_page = page.find('/services/datacenter') %}
<li>{{ datacenter_page.menu() }}</li>
</ul>
{% else %}
{{ parent() }}
{% endif %}
{% endblock %}
{% block content %}
{{ page.content }}
{% for module in page.collection() %}
<div id="{{ _self.pageLinkName(module.menu) }}"></div>
{{ module.content }}
{% endfor %}
{% endblock %}
The 'rechenzentrum' link is rendered correctly, and copying the link location via right click gives a correct URL that opens a seemingly correct page. So the template rendering is fine.
The link has two onclick handlers attached to it, though. Probably one of them fails and thus prevents navigation. (The JS is minified so I did not try to debug it.)

Resources