4

I've added a custom twig template for links--language-block.html.twig.

Inside of it, I want to render additional HTML when the current item is active. But I can't figure out how to check when the current item is active.

{% if links -%}
  {%- if attributes.hasClass('inline') -%}
  <ul{{ attributes.addClass('list-inline') }}>
  {%- else -%}
  <ul{{ attributes }}>
  {%- endif -%}
    {%- for key, item in links -%}

      {% if item.attributes.hasClass('is-active') %} << this is always false
        <li>foobar</li>
      {%- endif -%}

      <li{{ item.attributes.addClass('dropdown') }}>
        {%- if item.link -%}
          {{ item.link }}

          {# <a class="dropdown-toggle" data-target="#" data-toggle="dropdown">Deutsch <span class="caret"></span></a> #}
        {%- elseif item.text_attributes -%}
          <span{{ item.text_attributes }}>{{ item.text }}</span>
        {%- else -%}
          {{ item.text }}
        {%- endif -%}
      </li>
    {%- endfor -%}
  </ul>
{%- endif %}

How can I check if the link as the active class?

  • 1
    When you inspect element, do you see the is-active class? – No Sssweat May 23 '16 at 14:32
  • @NoSssweat in the end result yes, but not in the twig template. even using kint the final a tag has not the active class, only in the browser. it is not javascript, i've checked that – Alex May 24 '16 at 6:29
  • An alternative would be to get the current page url or the node title and use that as your if statement. – No Sssweat May 24 '16 at 7:17
  • Having the same issue. Did you manage to figure out why this is not working? – Eduard Luca Jun 10 '16 at 14:00
  • 1
    @leymannx, yes, this is the best choice. For anonymous requests there is also a PHP option in a response subscriber, see drupal.stackexchange.com/a/235108/47547 – 4k4 Jul 24 '19 at 16:18
3
+75

In some cases, the active state is not set by design due potential problems with caching. This behavior is documented in this change record.

Setting the active class is now an opt-in feature:

l() and LinkGenerator::generate() now have a set_active_class option that defaults to FALSE theme_links() now accepts a set_active_class key that defaults to FALSE Those links that you'd expect to get the active class set, do get it: menu links, language switching links …

The output of l(), LinkGenerator::generate() and theme_links() no longer contains the active class, even if you do opt in. Instead, they get a data-drupal-link-system-path attribute, and if there's a GET query, they also get a data-drupal-link-query attribute…

In those cases, where it is not set on server side, you can take a look at core/misc/active-link.js to get an idea how to manipulate the active state on client side.

| improve this answer | |
  • Yes this behaviour can be confusing to those of us used to how things worked in previous versions of Drupal. Wasted a lot of time figuring this out for myself. – Alfred Armstrong Jul 25 '19 at 14:29
1

It seems you can just use "is_active". This works for me:

{% set link = link|merge({ '#attributes': { 'class': [ 'classes', 'if', 'active'] } }) %}
{% if is_active %}
{% set link = link|merge({ '#attributes': { 'class': [ 'classes', 'if', 'not', 'active'] } }) %}
{% endif %}

<li{{ attributes.addClass('nav-item') }} role="presentation">{{ link }}</li>
| improve this answer | |
  • Really? Even in a cached and unauthenticated session? – leymannx Jul 24 '19 at 17:53
  • Cant find a menu where I use this where the user is not logged in. Will get back to you if I find a case. – coderama Jul 24 '19 at 17:59
1

In Drupal 8 the "is-active" class is added in two different ways:

  • For anonymous users it's added in the server side.
  • For authenticated users it's using javascript to add the class, as this allows for better cacheability.

You might consider adding the <li> in JS when the DOM is ready, to make sure the class has been added to the DOM.

| improve this answer | |
0

For core/themes/classy/templates/navigation/menu.html.twig:

{#
/**
 * @file
 * Theme override to display a menu.
 *
 * Available variables:
 * - menu_name: The machine name of the menu.
 * - items: A nested list of menu items. Each menu item contains:
 *   - attributes: HTML attributes for the menu item.
 *   - below: The menu item child items.
 *   - title: The menu link title.
 *   - url: The menu link url, instance of \Drupal\Core\Url
 *   - localized_options: Menu link localized options.
 *   - is_expanded: TRUE if the link has visible children within the current
 *     menu tree.
 *   - is_collapsed: TRUE if the link has children within the current menu tree
 *     that are not currently visible.
 *   - in_active_trail: TRUE if the link is in the active trail.
 */
#}

Then you can write:

{% if item.in_active_trail %}
   <li>foobar</li>
{% endif %}
| improve this answer | |
0

Define a JS library with a dependency on the core/drupal.active-link library:

mytheme/mytheme.libraries.yml

remove-active-links:
  version: 1.x
  js:
    js/remove-active-links.js: { }
  dependencies:
    - core/jquery
    - core/drupal
    - core/drupal.active-link

Then your JS code knows which link has an is-active class and you can add HTML or remove the link wrapper like in this example:

mytheme/js/remove-active-links.js

(function ($, Drupal) {

  'use strict';

  Drupal.behaviors.removeActiveLinks = {
    attach: function (context) {

      $(context).find('a.is-active').contents().unwrap();

    }
  };

})(jQuery, Drupal);

For more info and an alternative PHP solution (only for anonymous requests) see this answer Don't link menu in the active page

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.