Navlink Stay Active When URL Partially Match

Hi,

I’m on node.js and need to create the navlink to stay active after navigating to other pages that have partially matched URLs.

Example:
domain.com/order/
domain.com/order/abc1234567890

Does anybody know how to achieve this? Is there any relation to URL rewriting?

thank you!

Moved to feature requests, I’m also looking for this

I proposed somewhere in a topic the following attribute: dmx-match-href

The topic doesn’t seem to be available right now (was probably hidden) as it was part of another feature request that was already completed

The usage of the suggested attribute would be like this:

<a dmx-match-href="/order/" class="nav-link active" is="dmx-link" href="/order/abc1234567890">View order</a>

This might actually be somewhat an easy fix on dmxBootstrap5Navigation.js

Is it possible to achieve this using a class toggle? But don’t know how to create the condition.
Tried using below condition but still did not work as expected.
dmx-class:active=“browserSidemenu.location.pathname.contains(‘order’)”

Hi,

I’m not sure if it’s possible to use a class toggle, because the script then would override that active toggle. Even if it’s ok I’m also not experienced enough in the front-end to build the condition

I spent a few minutes modifying dmxBootstrap5Navigation.js if you want to try (I assume you’re using Bootstrap 5):

(function() {

  // Call init when DOM is ready
  if (document.readyState === 'loading') { // Loading hasn't finished yet
    document.addEventListener('DOMContentLoaded', _init, { once: true });
  } else { // DOMContentLoaded has already fired
    _init();
  }

  function _init() {
    // Listen to url changes
    window.addEventListener('popstate', _update);
    window.addEventListener('pushstate', _update);

    // Listen to DOM changes and call update when nodes are added
    new MutationObserver(_update).observe(document.body, { subtree: true, childList: true });

    // Initial update
    _update();
  }

  function _update() {
  	var url = window.location.href;

  	document.querySelectorAll('a.nav-link:not([data-bs-toggle]), a.dropdown-item').forEach(function(elem) {
      let match = url.startsWith(elem.getAttribute('dmx-match-href'));
      elem.classList.toggle('active', match || elem.href == url || elem.href == url.split("?")[0].split("#")[0]);
  	});

    document.querySelectorAll('a.dropdown-item.active').forEach(function(elem) {
      var theItem = elem.closest('.nav-item.dropdown');
      if (theItem) {
        var theToggle = theItem.querySelector('.dropdown-toggle');
        if (theToggle) {
          theToggle.classList.toggle('active');
        }
      }
  	});
  }

})()

And also use the dmx-match-href attribute as exampled in the previous post

Yes I’m using bootstrap 5.
Thanks let me try this…

I’m testing too, didn’t work but I’m working on it, need to fix a condition, will reply in a few minutes

Fixed version, let me know how it works:

(function() {

  // Call init when DOM is ready
  if (document.readyState === 'loading') { // Loading hasn't finished yet
    document.addEventListener('DOMContentLoaded', _init, { once: true });
  } else { // DOMContentLoaded has already fired
    _init();
  }

  function _init() {
    // Listen to url changes
    window.addEventListener('popstate', _update);
    window.addEventListener('pushstate', _update);

    // Listen to DOM changes and call update when nodes are added
    new MutationObserver(_update).observe(document.body, { subtree: true, childList: true });

    // Initial update
    _update();
  }

  function _update() {
  	var url = window.location.href;

  	document.querySelectorAll('a.nav-link:not([data-bs-toggle]), a.dropdown-item').forEach(function(elem) {
      let mAttr = elem.getAttribute('dmx-match-href');
      let urlObj = new URL(url);
      let match = urlObj.pathname.startsWith(mAttr);
      //console.log("match", match, "mAttr", mAttr, "url", url);
      elem.classList.toggle('active', match || elem.href == url || elem.href == url.split("?")[0].split("#")[0]);
  	});

    document.querySelectorAll('a.dropdown-item.active').forEach(function(elem) {
      var theItem = elem.closest('.nav-item.dropdown');
      if (theItem) {
        var theToggle = theItem.querySelector('.dropdown-toggle');
        if (theToggle) {
          theToggle.classList.toggle('active');
        }
      }
  	});
  }

})()

P.S.: This doesn’t survive Wappler updates, the team will eventually need to add this on their core files

Should I put dmx-match-href=“/order/” inside the ‘domain.com/order’ nav link or just inside the ‘domain.com/order/1234567890’ ?

The aim is to put in your existing navlink domain.com/order so you don’t need many changes

Seems like still not working

I put the dmx-match-href="/order/ inside this sidemenu nav-link
<a dmx-match-href="/order/" class="nav-item nav-link sidemenu" href="/order" internal>

and for the link to go this page is here
<a href="/order/{{tableRepeat1[0].order_id}}" internal>Your link title</a>

I double-checked my website, it’s working on mine

Are you sure you’re using the latest dmxBootstrap5Navigation.js I posted? The fixed version, and then try to CTRL+F5 to reload the page without cache

Also see if you have any errors on browser console

I mostly prefer to add the class toggle myself using dmx-class:active="browser1.pathname.startsWith('/order')". It requires the browser component on the page but is very flexible to use and works on all kind of navigation menus, not only bootstrap.

The dmxBootstrap5Navigation was to automate the toggling for you so that it is not needed to add your own logic. This works fine in most cases but will not cover the needs for everyone.

2 Likes

I did copy and pasted the whole code to dmxBootstrap5Navigation.js, but unfortunately still not working. Checking on the console there is no error either. Since 0 knowledge of javascript, I might be lost to understand how to do it.

I put this element inside partials and the browser component are in the main layout.
Somehow I can’t find the browser from the data picker, should I add browser component also inside the partials?

Instead of browser1.pathname should be browser1.location.pathname

I’ve also observed dmxBootstrap5Navigation will remove the active class in this case, making it look like it’s doing nothing. Do you have a way to inhibit this removal just for this nav-link?

Try removing the nav-link class from the link this is something I did worked on one of my menus to stop the auto adding and removing of the active class

Hey,

Thanks for the tip - just worried if it would break web accessibility (for screen readers and alike)

Edit: Breaks styling

Ah yeah my menu was mainly custom css had a feeling it might not work on most menus

Another thing that I just had a look at was what if you go into code view and add
data-bs-toggle="" to the nav item

or in dmxBootstrap5Navigation you could add a additional :not on this line with a class for example unlink and then add this class to the nav item

document.querySelectorAll('a.nav-link:not([data-bs-toggle]), a.dropdown-item').forEach(function (elem) {

to

document.querySelectorAll('a.nav-link:not([data-bs-toggle]):not(.unlink), a.dropdown-item').forEach(function (elem) {

This might get reset on each new Wappler update though unless Patrick could add this for us :slight_smile:

1 Like