Why is setTimeout not working with .hover()?

2.8k Views Asked by At

JSFIDDLE: http://jsfiddle.net/yL1uu0hv/

I'm trying to create a simple hoverintent using setTimeout. I'm not sure what the problem is with the provided code. If I comment out hovertimer = setTimeout(function(){ and }, 500); then the addClass I'm using works. If the aforementioned items are active (not commented out), addClass doesn't work.

I'm also getting some kind of error due to the syntax of $('ul#megamenulist li').each($(this).addClass(opts.mmactiveclass.mmclassname)); and it keeps bubbling even with doing nothing.

What's supposed to happen is that after X milliseconds of hovering over the item, the class 'active' is supposed to be added to the hovered 'li' tag. If not hovered over for X milliseconds or longer, 'active' is not added. And, if 'active' is added, on mouseleave the class 'active' should be removed.

Any help is greatly appreciated.

jQuery(document).ready(function($){
        $('ul#megamenulist li').hover(
            function(){
                console.log('over');
                //hovertimer = setTimeout(function(){
                    $('ul#megamenulist li').each($(this).addClass('active'));
                //}, 500);

            },
            function(){
                console.log('off');
                clearTimeout(hovertimer);
                $('ul#megamenulist li').removeClass('active');
            }
        );
});


<div id="megamenunav">
    <ul id="megamenulist">
        <li>
            <a href="#"><span>Explore</span></a>
        </li>
        <li>
            <a href="#"><span>Develop</span></a>
        </li>
        <li>
            <a href="#"><span>Engage</span></a>
        </li>
        <li>
            <a href="#"><span>Shop</span></a>
        </li>
        <li>
            <a href="#"><span>About</span></a>
        </li>
    </ul>
</div>
1

There are 1 best solutions below

3
On BEST ANSWER

The problem is that the context inside setTimeout function (this keyword) is global window object. The simplest fix for this is to save reference to ul#megamenulist li element in variable and use it inside setTimeout.

Correct code:

var $li = $('ul#megamenulist li').hover(
    function () {
        var self = this;
        hovertimer = setTimeout(function(){
            $(self).addClass('active');
        }, 500);
    },
    function () {
        clearTimeout(hovertimer);
        $li.removeClass('active');
    }
);

Also it's a good practice to cache jQuery collections to avoid repetitive DOM queries. For example you can cache it like in the code above, since hover returns a collection.

Demo: http://jsfiddle.net/yL1uu0hv/2/