javascripthtmlfrontend

Is there a way I can reuse a toggle function for a list of navigation items that have a drop down when clicked?


Here I have 3 addEventListeners that call a function when clicked to open a drop down menu according to which nav item is clicked.

My problem is once it the first menu item is clicked it opens and closes just fine but the rest of them do not work.

document.getElementById('product-menu').addEventListener('click', openMenu);
document.getElementById('company-menu').addEventListener('click', openMenu);
document.getElementById('connect-menu').addEventListener('click',openMenu);

function openMenu(){
    document.getElementById('dropdown-menu').classList.toggle('active')
};

I was trying to allow the reuse of the toggle function to open up the dropdown-menu on each nav item.

Here is the HTML requested to be attached to this.

 <li id="product-menu" class="dropdown">
      <a class="drop-item" href="#" >Product<img src="images/icon-arrow-dark.svg" alt=""/></a>
      <ul id="dropdown-menu" >
        <li><a href="#">Overview</a></li>
        <li><a href="#">Pricing</a></li>
        <li><a href="#">MarketPlace</a></li>
        <li><a href="#">Features</a></li>
        <li><a href="#">Integrations</a></li>
      </ul>
    </li>

    <li id="company-menu" class="dropdown"></li>
      <a class="drop-item" href="#">Company<img src="images/icon-arrow-dark.svg" alt=""/></a>
      <ul id="dropdown-menu">
        <li><a href="#">Overview</a></li>
        <li><a href="#">Pricing</a></li>
        <li><a href="#">MarketPlace</a></li>
        <li><a href="#">Features</a></li>
        <li><a href="#">Integrations</a></li>
      </ul>
    </li>

    <li id="connect-menu" class="dropdown"></li>
      <a class="drop-item" href="#">Connect<img src="images/icon-arrow-dark.svg" alt=""/></a>
      <ul id="dropdown-menu">
        <li><a href="#">Overview</a></li>
        <li><a href="#">Pricing</a></li>
        <li><a href="#">MarketPlace</a></li>
        <li><a href="#">Features</a></li>
        <li><a href="#">Integrations</a></li>
      </ul>
    </li>


Solution

  • IDs have to be unique, you can't reuse id="dropdown-menu" in each submenu.

    You should use a class, instead: <ul class="dropdown-menu">. Then in the listener function you can use

    this.querySelector(".dropdown-menu").classList.toggle("active");
    

    Full code:

    document.querySelectorAll("li.dropdown").forEach(li => li.addEventListener("click", openMenu));
    
    function openMenu() {
      this.querySelector('.dropdown-menu').classList.toggle('active')
    };
    ul.dropdown-menu {
      display: none;
    }
    
    ul.dropdown-menu.active {
      display: block;
    }
    <ul>
      <li id="product-menu" class="dropdown">
        <a class="drop-item" href="#">Product<img src="images/icon-arrow-dark.svg" alt=""/></a>
        <ul class="dropdown-menu">
          <li><a href="#">Overview</a></li>
          <li><a href="#">Pricing</a></li>
          <li><a href="#">MarketPlace</a></li>
          <li><a href="#">Features</a></li>
          <li><a href="#">Integrations</a></li>
        </ul>
      </li>
    
      <li id="company-menu" class="dropdown">
        <a class="drop-item" href="#">Company<img src="images/icon-arrow-dark.svg" alt=""/></a>
        <ul class="dropdown-menu">
          <li><a href="#">Overview</a></li>
          <li><a href="#">Pricing</a></li>
          <li><a href="#">MarketPlace</a></li>
          <li><a href="#">Features</a></li>
          <li><a href="#">Integrations</a></li>
        </ul>
      </li>
    
      <li id="connect-menu" class="dropdown">
        <a class="drop-item" href="#">Connect<img src="images/icon-arrow-dark.svg" alt=""/></a>
        <ul class="dropdown-menu">
          <li><a href="#">Overview</a></li>
          <li><a href="#">Pricing</a></li>
          <li><a href="#">MarketPlace</a></li>
          <li><a href="#">Features</a></li>
          <li><a href="#">Integrations</a></li>
        </ul>
      </li>
    </ul>