Search code examples
jqueryhtmlcssancestor

jQuery function still fires with the wrong class


I'm trying to create a nav that is optimized for mobile.

 <nav id="nav-content" class="nav-main">       
                <ul>
                    <li>
                        <a href="">about</a>
                    </li>
                    <li>
                        <a class="parent-link">production</a>
                        <ul class="sub-menu">
                            <li><a href="">workshops</a></li>
                            <li><a href="">shows</a></li>
                            <li><a href="">greenlite</a></li>
                        </ul>
                    </li>
                    <li><a href="">watch</a></li>
                    <li><a id="link-logo" href="index.html"><div id="logo"></div></a></li>
                    <li>
                        <a class="parent-link">members</a>
                        <ul class="sub-menu">
                            <li><a href="">current</a></li>
                            <li><a href="">prospective</a></li>
                        </ul>
                    </li>
                    <li>
                        <a class="parent-link">postings</a>
                        <ul class="sub-menu">
                            <li><a href="">jobs</a></li>
                             <li><a href="">auditions</a></li>
                        </ul>
                    </li>
                    <li>
                        <a class="parent-link">contact</a>
                       <ul class="sub-menu">
                           <li><a href="">team</a></li> 
                           <li><a href="">advertise</a></li>
                           <li><a href="">suggestions</a></li>  
                        </ul>
                    </li>
                </ul>

            </nav>

            <nav id="nav-mobile-header"><a href="index.html"><div id="logo-small"></div></a><div id="nav-trigger">
                ☰
             </div></nav>  

The nav class changes correctly from from .nav-main to .nav-mobile when the window becomes less than 1000px.

$(document).ready(function()
{

    $(function () {
    $(window).resize(function () { 
        if ($(window).width() <= 1000) 
        {
            $('#nav-content').removeClass('nav-main').addClass('nav-mobile');
        }
        else
            {
                $('#nav-content').removeClass('nav-mobile').addClass('nav-main');
                if ($('#wrap').hasClass('to-left'))
                    {
                        $('#wrap').removeClass('to-left');
                    }
            }

    }).resize(); 
});
});

I have a sliding down menu set up on hover when the class of nav is .nav-main. However, this query is still fired when .nav-mobile is the class of the nav. Why does this happen? Why is there still an event listener for the links even though the class is changed?

$(document).ready(function()
{
    var slideTime = 300;
        $('.nav-main li').hover(function () //why does this still work for .nav-mobile?
        {

            $('.sub-menu', this).stop().slideDown(slideTime);
            $('.parent-link', this).css('color', '#555');

        },function () 
        {
            $('.sub-menu', this).stop().slideUp(slideTime);
            $('.parent-link', this).attr('style', '');
        });


});

Any help is appreciated, I'm still relatively new to jQuery and SO.


Solution

  • The reason why you still have $('.nav-main li').hover(function () executing is because how that event is being registered. It's basically binding an event vsdelegating an event.

    Binding an event :

    $('.nav-main li').hover(function () -> binding a hover event to element. When you bind an event, it's registered in the memory to that element. If the attributes or properties of the elements are changed, it would not impact the event since its binded to the element, not to it's attributes. So even if you change a class, the event would still be in memory. The way you can remove it is by using unbind event -> $('.nav-main li').unbind('hover');

    Delegating an event :

    Event delegation refers to the process of using event propagation (bubbling) to handle events at a higher level in the DOM than the element on which the event originated. It allows us to attach/detach a single event listener for elements that exist or don't exist now or in the future.

    Source : https://learn.jquery.com/events/event-delegation/

    $(document).on('mouseover','.nav-main li',function () -> 
    

    delegating a mouseover-mouseleave event to an element inside the document.

    When you delegate an event to the document, the memory keeps a track of elements inside the document (DOM). Any changes to the property or attributes like class to the element removes it from the memory and is not more applicable to that element.

    Here are 2 examples which shows the theory in action :

    Binding : http://jsfiddle.net/DinoMyte/p8ARq/619/

    Delegating : http://jsfiddle.net/DinoMyte/p8ARq/620/

    So, you should replace your hover binding to mouseenter-mouseleave delegation.