Home > Software design >  How to know the logic of multilevel menu event bubbling
How to know the logic of multilevel menu event bubbling

Time:11-12

I'm trying to understand the logic happening in my basic multilevel menu click event. I understood what happening on clicking on "About" menu in the navigation. And it works as per my expecation of code. But when i click on "Profile" menu (Submenu of "About" menu), JS makes it's sublevel menu "display:none". I tried to think in the aspect of even bubbling. But eventhough the bubbling happens here, it should not be working like this. Actually for me, its really complicated to understand how JS works here. It would be a Great Help if anyone can explain with a simple and understandable way. Thank You Very Much in Advance!!!

let menus = document.querySelectorAll(".main-navigation ul li a");
    menus.forEach((item) => {
        if (item.parentElement.querySelector("ul")) {
            item.parentElement.classList.add("has-submenu");
        }
    });

    let submenu = document.querySelectorAll(".has-submenu");
    submenu.forEach((item) => {
        item.addEventListener("click", (e) => {
            e.preventDefault();
            let ul = e.target.parentElement.querySelector("ul");
            let cs = window.getComputedStyle(ul).display;
            
            if (cs === "none") {
                ul.style.cssText = "display:block";
            }
            else {
                ul.style.cssText = "display:none";
            }


        });
    });
.main-navigation ul {list-style:none;margin:0;padding:0;font-family:arial;}
    .main-navigation ul li {padding:.35rem;background:#f9f9f9;}
    .main-navigation ul li ul {padding-left:1rem;display:none;}
    .main-navigation ul li a {display:block;text-decoration:none;}
<div class="main-navigation">
<ul>
    <li><a href="">Home</a></li>
    <li><a href="">About  </a>
    <ul>
      <li><a href="">Profile  </a>
      <ul>
       <li><a href="">History</a></li>
       <li><a href="">Management</a></li>
      </ul>
      </li>
      <li><a href="">Vision</a></li>
      <li><a href="">Mission</a></li>
    </ul>
    </li>
    <li><a href="">Services  </a>
    <ul>
      <li><a href="">Web Design</a></li>
      <li><a href="">Web Development</a></li>
    </ul>
    </li>
    <li><a href="">Contact</a></li>
</ul>   
</div>
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

CodePudding user response:

Solution

If you add a console.log inside your click handler you will notice that the event for the nested item is called twice.

You probably knew that it could happen and you used preventDefault.

However, preventDefault is for the browser's default effects (for example, it prevents your page to refresh as you put an href attribute) but in your case the double behaviour is from your own custom listener.

This means, you need to add stopPropagation that prevents further propagation of the current event in the capturing and bubbling phases.

Working Demo

let menus = document.querySelectorAll(".main-navigation ul li a");
menus.forEach((item) => {
  if (item.parentElement.querySelector("ul")) {
    item.parentElement.classList.add("has-submenu");
  }
});

let submenu = document.querySelectorAll(".has-submenu");
submenu.forEach((item) => {
  item.addEventListener("click", (e) => {
    e.preventDefault();
    e.stopPropagation();
    let ul = e.target.parentElement.querySelector("ul");
    let cs = window.getComputedStyle(ul).display;

    if (cs === "none") {
      ul.style.cssText = "display:block";
    } else {
      ul.style.cssText = "display:none";
    }
  });
});
.main-navigation ul {
  list-style: none;
  margin: 0;
  padding: 0;
  font-family: arial;
}

.main-navigation ul li {
  padding: .35rem;
  background: #f9f9f9;
}

.main-navigation ul li ul {
  padding-left: 1rem;
  display: none;
}

.main-navigation ul li a {
  display: block;
  text-decoration: none;
}
<div class="main-navigation">
  <ul>
    <li><a href="">Home</a></li>
    <li><a href="">About  </a>
      <ul>
        <li><a href="">Profile  </a>
          <ul>
            <li><a href="">History</a></li>
            <li><a href="">Management</a></li>
          </ul>
        </li>
        <li><a href="">Vision</a></li>
        <li><a href="">Mission</a></li>
      </ul>
    </li>
    <li><a href="">Services  </a>
      <ul>
        <li><a href="">Web Design</a></li>
        <li><a href="">Web Development</a></li>
      </ul>
    </li>
    <li><a href="">Contact</a></li>
  </ul>
</div>
<iframe name="sif2" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

  • Related