简体   繁体   中英

Disable click from registering on parent li after child ul is clicked

var treeview = document.querySelectorAll(".treeview");
var submenu = document.querySelectorAll(".treeview ul");
for (var i=0; i<treeview.length; i++;) {
    treeview[i].addEventListener("click", function(e) {
    this.classList.toggle("menu-open");
    e.stoppropagation();
});

The sub menu (treeview-menu) opens when there is a click on li but if the child ul links are click it closes the menu since click gets registered.

<li class="treeview">
          <a href="#">
            <i class="fa fa-dashboard"></i> <span>Dashboard</span>
          </a>
          <ul class="treeview-menu">
            <li><a href="index.html"><i class="fa fa-circle-o"></i> Dashboard v1</a></li>
            <li class="active"><a href="index2.html"><i class="fa fa-circle-o"></i> Dashboard v2</a></li>
          </ul>
   </li>

my failed attempt as below :

var treeview = document.querySelectorAll(".treeview");
var submenu = document.querySelectorAll(".treeview ul");
for (var i=0; i<treeview.length; i++) {
    treeview[i].addEventListener("click", function(e) {
    this.classList.toggle("menu-open");
    e.stoppropagation();
    submenu[i].addEventListener("click", function() {
        e.stoppropagation();
    })
});

Worked for me

    var treeview = document.querySelectorAll(".treeview");
    var submenu = document.querySelectorAll(".treeview ul");
    for (var i=0; i<treeview.length; i++) {
        treeview[i].addEventListener("click", function() {
        this.classList.toggle("menu-open");
    for (var x=0; x<treeview.length; x++){  
        submenu[x].addEventListener("click", function(e) {
            e.stopPropagation();
        })
      }
     });
    }

There are several issues in your code:

  • The spelling of stopPropagation is wrong
  • Unclosed brace, mostly because the indentation is off
  • The inner event handler references an i that has already passed beyond the length of the treeview list. Be aware that the loop has finished before any clicking happens. So inside a click handler i is not related to a certain iteration of the loop. You can solve this with giving i block scope (using let )
  • The inner event handler references an e object that belongs to another event, as you did not define it as parameter
  • You assume that every .treeview has exactly one ul child, otherwise the index of related sub menus will not correspond.

Apart from the last point, the following works in your particular example:

for (let i=0; i<treeview.length; i++) { // block scope
    treeview[i].addEventListener("click", function(e) {
        this.classList.toggle("menu-open");
        e.stopPropagation(); // Spelling!
        submenu[i].addEventListener("click", function(e) { // <-- pass e
            e.stopPropagation(); // Spelling!
        });
    });
} // Fix brace

However, because .treeview elements might in theory have 0 or more than 1 child ul , the above solution is not generic enough. I would even suggest to only capture clicks on the .treeview > a element, and then you don't even have this propagation issue:

 for (const link of document.querySelectorAll(".treeview > a")) { link.addEventListener("click", function(e) { this.parentNode.classList.toggle("menu-open"); }); } 
 .menu-open > ul.treeview-menu { display: block } .treeview > ul { display: none } 
 <li class="treeview"> <a href="#"> <i class="fa fa-dashboard"></i> <span>Dashboard</span> </a> <ul class="treeview-menu"> <li><a href="#"><i class="fa fa-circle-o"></i> Dashboard v1</a></li> <li class="active"><a href="#"><i class="fa fa-circle-o"></i> Dashboard v2</a></li> </ul> </li> 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM