Graphic Detail
Graphic Detail

Reputation: 121

jQuery: How can I get sub-menus to stay open when clicking sub-sub-menus

There appear to be a few topics related to this already, but none of their answers seem to quite work for me.

So, I'm building a Wordpress theme and I want it to have the ability to have sub-menus and sub-sub-menus, etc. So I end up with a menu structure a bit like this:

<ul id="menu-main-navigation-menu" class="menu">
  <li class="menu-item menu-item-type-post_type menu-item-object-page menu-item-home current-menu-item page_item current_page_item"><a href="" aria-current="page">Home</a></li>
  <li class="menu-item menu-item-type-post_type menu-item-object-page"><a href="">Products</a></li>
  <li class="menu-item menu-item-type-post_type menu-item-object-page menu-item-has-children"><a href="">Services</a>
    <ul class="sub-menu">
      <li class="menu-item menu-item-type-post_type menu-item-object-page"><a href="">Basic</a></li>
      <li class="menu-item menu-item-type-post_type menu-item-object-page"><a href="">Intermediate</a></li>
      <li class="menu-item menu-item-type-post_type menu-item-object-page menu-item-has-children"><a href="">Advanced</a>
        <ul class="sub-menu">
          <li class="menu-item menu-item-type-post_type menu-item-object-page"><a href="">Advanced Service 1</a></li>
          <li class="menu-item menu-item-type-post_type menu-item-object-page"><a href="">Advanced Service 2</a></li>
        </ul>
      </li>
    </ul>
  </li>
</ul>

So, li's that have child ul's have the class "menu-item-has-children", which is their only distinguishing feature from any other li's.

Now, in jQuery I have tried this:

jQuery(document).on('click','.menu-item-has-children',function(){
  jQuery(this).toggleClass('active');
});

But the problem with this is that when I click on a ".menu-item-has-children" that is within a ".menu-item-has-children", I am effectively clicking on both at once, so the sub-sub-menu gets the class ".active" added to it and opens it as it should, but it's parent sub-menu loses it's ".active" class, thereby collapsing both.

My goal is that each time I click on a sub-menu, if it's closed then it should open, or if it's opened it should close. Each time I click on a sub-sub-menu, it should open and close accordingly, but it's parent sub-menu should remain open. This should also work for sub-sub-sub-menus and sub-sub-sub-sub-menus, etc... so I really need a universal solution that will work no matter how deeply nested a sub-menu is.

Upvotes: 0

Views: 736

Answers (1)

Xhynk
Xhynk

Reputation: 13840

Take a look at the documentation for event.stopPropagation(). At a basic level, it prevents the current event from "bubbling up" through parent elements. Here's a super rudimentary example based on the snippets you've provided.

You can also add other checks into your click handler, such as determining whether or not an item has a class, or children - but at a base level, the easiest thing to do is stop propagation through parent elements.

jQuery(document).on('click', '.menu-item-has-children', function(e){
  e.stopPropagation();
  jQuery(this).toggleClass('active');  
});
.menu > li {
  display: block;
}

.sub-menu {
  display: none;
}

.active > .sub-menu {
  display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul id="menu-main-navigation-menu" class="menu">
  <li class="menu-item menu-item-type-post_type menu-item-object-page menu-item-home current-menu-item page_item current_page_item"><a href="#" aria-current="page">Home</a></li>
  <li class="menu-item menu-item-type-post_type menu-item-object-page"><a href="#">Products</a></li>
  <li class="menu-item menu-item-type-post_type menu-item-object-page menu-item-has-children"><a href="#">Services</a>
    <ul class="sub-menu">
      <li class="menu-item menu-item-type-post_type menu-item-object-page"><a href="#">Basic</a></li>
      <li class="menu-item menu-item-type-post_type menu-item-object-page"><a href="#">Intermediate</a></li>
      <li class="menu-item menu-item-type-post_type menu-item-object-page menu-item-has-children"><a href="#">Advanced</a>
        <ul class="sub-menu">
          <li class="menu-item menu-item-type-post_type menu-item-object-page"><a href="#">Advanced Service 1</a></li>
          <li class="menu-item menu-item-type-post_type menu-item-object-page"><a href="#">Advanced Service 2</a></li>
        </ul>
      </li>
    </ul>
  </li>
</ul>

Upvotes: 1

Related Questions