Home > Enterprise >  jQuery nested hover events removeClass() on mouseleave issue
jQuery nested hover events removeClass() on mouseleave issue

Time:11-03

I have a nested list that looks like this:

<ul >
    <li>
        <a href="#">Menu item</a>
        <ul >
            <li>
                <a href="#">Subitem-1</a>
                <ul>
                <li>Sub-Subitem-1</li>
                <li>Sub-Subitem-2</li>
                <li>Sub-Subitem-3</li>
                </ul>
            </li>
            <li>
                <a href="#">Subitem-2</a>
                <ul>
                <li>Sub-Subitem-1</li>
                <li>Sub-Subitem-2</li>
                <li>Sub-Subitem-3</li>
                </ul>
            </li>
        </ul>
    </li>
</ul>

When hovering the ul.menu-wrapper > li item, an .active class is applied to the first ul.sub-menu and the first li item within the submenu list:

$('ul.menu-wrapper').children().hover(
    function() {
        let subMenu = $(this).find('ul.sub-menu').first()
        subMenu.addClass('active')
        subMenu.children().first().addClass('active')
    },
    function() {
        let subMenu = $(this).find('ul.sub-menu').first()
        subMenu.removeClass('active')
    }
)

Now I need to hover the li items within the ul.sub-menu and change the .active class to the item being hovered.

I can do this by adding a .hover() method on the subMenu.children() items.

$('ul.menu-wrapper').children().hover(
    function() {
        ...
        subMenu.children().hover(
            function() {
                $(this).addClass('active')
            },
            function() {
                $(this).removeClass('active')
            }
        )
    },
    function() {
        ...
    }
)

When a submenu item has been hovered and the pointer goes back to the ul.menu-wrapper > li item, I want to have at least one ul.sub-menu > li item with the .active class.

Currently the mouseleave method is removing the class when pointer is moved from a submenu back to the parent list item. How can I prevent this to always have one ul.sub-menu > li with .active class at all times?

Demo https://jsfiddle.net/5Lwyh3xs/

CodePudding user response:

On mouse out add active class to the first li if no li items have active class.

$('ul.menu-wrapper').children().hover(
  function() {
    let subMenu = $(this).find('ul.sub-menu').first()

    subMenu.addClass('active')
    subMenu.children().first().addClass('active')

    subMenu.children().hover(
      function() {
        $(this).addClass('active').siblings().removeClass('active')
      },
      function() {
        $(this).removeClass('active')
        if($('.sub-menu > li.active').length == 0) {
             subMenu.children().first().addClass('active')
        }
      }
    )
  },
  function() {
    let subMenu = $(this).find('ul.sub-menu').first()

    subMenu.removeClass('active')
  }
)
body {
  margin: 0;
  padding: 0;
}

ul {
  list-style-type: none;
  padding: 0;
  margin: 0;
}

ul.menu-wrapper {
  height: 80px;
}

ul.menu-wrapper {
  background: gray;
}

ul.menu-wrapper>li {
  height: 100%;
  display: flex;
  align-items: center;
}

ul.menu-wrapper ul.sub-menu {
  visibility: hidden;
  position: absolute;
  top: 80px;
}

ul.menu-wrapper ul.sub-menu.active {
  visibility: visible;
}

ul.menu-wrapper ul.sub-menu.active>li.active {
  background: darkmagenta;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<nav role="navigation" id="navigation-wrapper">
  <ul >
    <li>
      <a href="#">Menu item</a>
      <ul >
        <li>
          <a href="#">Subitem-1</a>
          <ul>
            <li>Sub-Subitem-1</li>
            <li>Sub-Subitem-2</li>
            <li>Sub-Subitem-3</li>
          </ul>
        </li>
        <li>
          <a href="#">Subitem-2</a>
          <ul>
            <li>Sub-Subitem-1</li>
            <li>Sub-Subitem-2</li>
            <li>Sub-Subitem-3</li>
          </ul>
        </li>
      </ul>
    </li>
  </ul>
</nav>

https://jsfiddle.net/y5qkb7mv/

  • Related