0

so I have a drop down navigation that appears on hover and I'm trying to get a delay in there to improve usability. Originally I was using hoverIntent which worked beautifully everywhere except on IE8 and below.

So instead I'm trying to do the delay with plain old Javascript but the setTimeout function won't call my jQuery.

var J = jQuery.noConflict();

 J(".navigation li").hover(function(){J(this).addClass("hover");},function(){setTimeout("J(this).removeClass('hover');",500);});      

When I set it up like this:

 function off(){J(this).removeClass("hover"); alert("hello");}


J(".navigation li").hover(function(){J(this).addClass("hover");},function(){setTimeout("off()",500);}); 

The alert works perfectly but not the .removeClass function.

Am I missing something?

1
  • 3
    The value of this in your "off()" function won't be what you need it to be. Commented Apr 25, 2012 at 15:06

3 Answers 3

9

this inside setTimeout is not the li element; i recommend you to use setTimeout overload that receives a function, and before set a variable to this to keep a reference:

J(".navigation li").hover(function(){
   J(this).addClass("hover");
},
function(){
  var self = this;
  setTimeout(function() {
         J(self).removeClass('hover');
  },500);
});
Sign up to request clarification or add additional context in comments.

Comments

1

Your off function:

function off() {
    J(this).removeClass("hover");
    alert("hello")
}

won't have the right this variable when called by setTimeout() - on most (all?) browsers it sets this to window.

You need an additional closure to wrap the original this and pass it to that timer function:

J(".navigation li").hover(
    function() {
        J(this).addClass("hover");
    },
    function() {
        var that = this;
        setTimeout(function() {
            off.apply(that);
        }, 500);
    }
);

NB: don't use string parameters to setTimeout() !

Comments

0

The problem is that this is referring to something different in the scope fo the timeout-callback.

The simplest solution would be to provide the old scope using jQuery.proxy([function],[scope])

<html>
    <head>
        <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
        <script>
            var f = function(){
                console.log(this.id);
            };

            $(function() {
                $("div").click(function () {
                    setTimeout($.proxy(f,this), 1000);
                });
            });
        </script>
    </head>
    <body>
        <div id="a">a</div>
        <div id="b">b</div>
    </body>
</html>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.