How can I keep my sub-menu open in jQuery hover menu?

12,757

Solution 1

I had a similar case, and solved it by splitting up the mouseover event into separate mouseenter and mouseleave events. Just pseudocode / an outline, but with your case try something like:

$("div#main-nav div").mouseenter(function() {
   // Check if sub menu is open, return if it is allready open
   // (I add a 'menu_open' class to sub menu when it is opened)

   // Code to hide open submenues
   // Code to open selected submenu      
});

Then use mouseleave and the toElement property of its event to check where the mousepointer went, if it went to a sub menu, do nothing, if not close all sub menues. Note that you need to hook up mouseleave events on the sub menues too. Something like this:

$("#main-nav div").mouseleave(function (event) {
   var toElem = $(event.toElement);
   if (toElem.closest("div.sub-nav").id=="subnav") return; // Prob nicer way to do this...point is to check if mouse enters a submenu, and if so stay open.
   // Close all open submenues, e.g. 
   $("#sub-nav ul").hide();
 });

 $("#subnav ul").mouseleave(function (event) {
    var toElem = $(event.toElement);
    if (toElem.closest("div.sub-nav").id=="subnav") return; // Check if entering submenu
    if (toElem.closest("div#main-nav")) return; // Check if entering main menu
    // Close all open submenues, e.g.
    $("#sub-nav ul").hide();
 });

Hope this is of some help to you. Just solved this myself, so haven't had time to polish it, I'm sure there are better and prettier ways to do this.

Solution 2

I had a similar situation, and unfortunately I wasn't able to reformat my entire menu to accommodate for the 'proper' parent/child structure.

If you simply call the sub-menu in the selector as well, it will remain 'open' during the hover state.

http://jsfiddle.net/K5P9Z/

Example -

jQuery(document).ready(function($) {

$('#kids, .menu-1').hover(function() {
    $('.menu-1').show();
}, function() {
    $('.menu-1').hide();
});
 $('#community, .menu-2').hover(function() {
    $('.menu-2').show();
}, function() {
    $('.menu-2').hide();
});
 $('#about, .menu-3').hover(function() {
    $('.menu-3').show();
}, function() {
    $('.menu-3').hide();
});

});​
Share:
12,757
alipica
Author by

alipica

Updated on June 05, 2022

Comments

  • alipica
    alipica almost 2 years

    I just started coding in jQuery last week and need some help figuring out how to make a menu work properly. I have 3 tabs each with their own menu. When a page is displayed a menu and a sub menu is automatically displayed. Once it's displayed the user can hover over the tabs to see the other sub menus and when they stop hovering the originally sub menu appears.

    My issue is that although, I can show them the sub menu of the other tabs, I can't keep the sub menu open for the user to click on a sub menu item. Other tutorials show how to do this only when the sub menu is nested within a parent element, but my code for the menu structure doesn't have the sub menus nested (this is how the code was when I joined the project). Is there some way I can keep the sub-menu open if the user hovers on the respective tab?

    Here is my menu HTML:

        <div id="navigation">
            <div id="main-nav">
                <div id="kids"><a href="../images/nav1.png"></a></div>
                <div id="community"><a href="../images/nav2.png"></a></div>
                <div id="about"><a href="../images/nav3.png"></a></div>
            </div>
        </div>
    
        <div id="sub-nav"> 
            <ul class="menu-1 requiresJS">
                <li><a href="#">Item1</a></li>
                <li><a href="#">Item2</a></li>
                <li><a href="#">Item3</a></li>
                <li><a href="#">Item4</a></li>
                <li><a href="#">Item5</a></li>
                <li><a href="#">Item6</a></li>
            </ul>
            <ul class="menu-2 requiresJS">
                <li><a href="#">Item1</a></li>
                <li><a href="#">Item2</a></li>
                <li><a href="#">Item3</a></li>
                <li><a href="#">Item4</a></li>
                <li><a href="#">Item5</a></li>
                <li><a href="#">Item6</a></li>
            </ul>
            <ul class="menu-3 requiresJS">
                <li><a href="#">Item1</a></li>
                <li><a href="#">Item2</a></li>
                <li><a href="#">Item3</a></li>
                <li><a href="#">Item4</a></li>
                <li><a href="#">Item5</a></li>
                <li><a href="#">Item6</a></li>
            </ul>
    

    Here is my jQuery thus far:

    // For JS users, display sub menus by default
    $(".requiresJS").css("display","block");
    
    var startMenu
    
    //hide all sub menus
    $("#sub-nav ul").hide();
    
    // check URL for about, community or kids and set startMenu with correct term
    if(window.location.href.indexOf("about") != -1){startMenu = "about"}
    else if(window.location.href.indexOf("community") != -1){startMenu = "community"}
    else{startMenu = "kids"}
    
    // highlight correct category tab
    $("div#main-nav #" + startMenu).addClass("selected");
    
    // show correct starting menu
    $("#sub-nav ul.menu-" + startMenu).show('slide', {direction: 'right'}, 600).effect("bounce", { times:1,direction:"right",distance:13 }, 300);
    
    // show correct menu on mouseover of div
    $("div#main-nav div").mouseover(function() {
    
        $("#sub-nav ul").stop(true, true)
        $("#sub-nav ul").hide();
    
        var currentId = $(this).attr('id');
    
        $("#sub-nav ul.menu-" + currentId).show();      
    });
    
    $("div#main-nav div").mouseover(function() {
            $("#sub-nav ul").stop(true, true)
            $("#sub-nav ul").hide();
            var currentId = $(this).attr('id');
            $("#sub-nav ul.menu-" + currentId).show();      
    });
    
  • alipica
    alipica over 12 years
    Interesting! I will have to try this. I ended up reformatting my whole menu and nesting everything like the tutorials say to do. It works, but it's good to know how to do it another way. Thanks!
  • TheBlackBenzKid
    TheBlackBenzKid almost 3 years
    This is a hidden gem of an answer!