skip to Main Content

We use JS for opening and closing nav panels on our website. Each navbar choice is an href link for when someone without JS enabled visits our website. We are using JS to intercept the link and open the panels via CSS changes.

The function works well for the first few times it is called, then fails and the default link is followed. There doesn’t seem to be a set number of iterations before it fails, but nvbtn3 seems to be the one that it fails on the most.

Not sure how to sort out a cure. It is almost like it gets overloaded and quits. Any suggestions?

Event delegation portion that looks for clicks on the navbar

$('mstrwrap').addEventListener('click', function(e) {
  // set eventlisteners for all A HREF links
  if (e.target.nodeName === 'A') {
    e.preventDefault();

    // check if is navbar link
    if ((e.target.id.includes('nvbtn'))) {
      // determine matching nav panel
      const nvpnl = e.target.id;
      const lk = 'nav' + nvpnl.match(/d+/g);
      // open nav panel
      openNav(lk, nvpnl);
    }
    // end if navbar link

  // lots more possible targets

  }
}

JS function for opening navigation menus

function openNav(x, y) {
  // if already open, close it
  if ($(x).style.maxHeight === '100vh') {
    // close
    $(x).style.maxHeight = '0';
    $(x).style.zIndex = '';
    $(y).classList.remove('nvopen');
    $('nvbar').classList.remove('nvopen2');
  }

  // close any that are open, then open target
  else {
    // close all pnl, open specified pnl
    const targets = document.querySelectorAll('[id^="nav"]');
    for (let i = targets.length; i--;) {
      targets[i].style.maxHeight = '0';
      targets[i].style.zIndex = '';
    }
    const nvbtns = document.querySelectorAll('[id^="nvbtn"]');
    for (let i = nvbtns.length; i--;) {
      nvbtns[i].classList.remove('nvopen');
    }
    $(x).style.maxHeight = '100vh';
    $(x).style.zIndex = '5';
    $(y).classList.add('nvopen');
    $('nvbar').classList.add('nvopen2');
  }
}

We use a pseudo jQuery style variable

var $ = function (selector) {
  return document.getElementById(selector);
};

The navbar is simple href links

<a href="https://example.com/menu1.htm" id="nvbtn1">Menu 1</a>
<a href="https://example.com/menu2.htm" id="nvbtn2">Menu 2</a>
<a href="https://example.com/menu3.htm" id="nvbtn3">Menu 3</a>

2

Answers


  1. Bergi was right in the comments, that’s why we ask to give the more details possible and ask for a reproducible example, because in simplifying the code for the question you got rid of the problem (trying to find the minimal example that cause your problem can help you solve it yourself, that’s a good thought process)

    Your links are not simply text, they have elements in them:

    <a class="xp" href="..." id="nvbtn3">Book <span class="nvt">|</span><span class="nvd">Now ✎</span> Ask Us </a>
    

    So your bug happens when you click on the small icon between the text, because the test if (e.target.nodeName === 'A') { } fails

    EDIT (probably simpler):
    There is another solution, using CSS pointer-events: none; on all elements inside your links, like the <span>. The event then should not trigger on the span but on the parent link instead.

    ORIGINAL:
    To solve this, you can use the following test, but be careful because changes in the structure of your <a> element can mess with it (a reliable solution would be to test the parent element recursively until you find you are in a link or not):

    if (e.target.nodeName === 'A' || (e.target.nodeName === 'SPAN' && e.target.parentNode.nodeName === 'A')) {
      //your code
    }
    

    You can add other tests, like the class of the <span> if it fits your use case.

    Login or Signup to reply.
  2. An alternative design proposal:

    Put the javascript disabled menu inside a <noscript>...</script> opening and closing tag pair. Possibly omit id attributes if they are only used for by JS, but not for styling.

    <noscript>
      <a href="https://example.com/menu1.htm">Menu 1</a>
      <a href="https://example.com/menu2.htm">Menu 2</a>
      <a href="https://example.com/menu3.htm">Menu 3</a>
    </noscript>
    

    Put the JS enabled menu(s) inside nav element(s) which have their style attributes set to none.

    <nav style="display: none">
        <a href="https://example.com/menu1.htm" id="nvbtn1">Menu 1</a>
        <a href="https://example.com/menu2.htm" id="nvbtn2">Menu 2</a>
        <a href="https://example.com/menu3.htm" id="nvbtn3">Menu 3</a>
    </nav>
    

    In JS startup code, after the body has been parsed, remove the display:none styling from nav elements:

    document.querySelectAll('nav').forEach(el=>{
        el.style.display="revert";
    }
    

    • This design should work in browsers where the client has gone to some trouble to turn JS off. It won’t work in browsers that don’t support CSS and element style attributes.

    • The major benefit would be that code to "intercept links" would no longer need to be written.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search