Ryan Saxe
Ryan Saxe

Reputation: 17869

jquery this not working with settimeout, bug?

so I am trying to do some dynamic hover manipulations, which require using this in jquery. For some reason that I cannot figure out, the javascript setTimeout function does not seem to support it.

I understand that the setTimeout function is not Jquery, but if placed inside a Jquery function, shouldn't it be able to respond to the relevant this?

Here is some sample code:

var go = false;
var t;
$('.box').mouseenter(function(){
    t = setTimeout(function(){
        go = true;
        alert($('span',this).text());
    },1000);
});
$('.box').mouseleave(function(){
    clearTimeout(t);
    if(go){
        alert($('span',this).text());
    }
});

when hovering for 1 second it will alert a blank, yet on mouseleave it will alert the correct text even though both alerts are inside a Jquery function with the same selector.

Why does this happen and how can I fix it?

jsfiddle

Upvotes: 4

Views: 3966

Answers (2)

Arun P Johny
Arun P Johny

Reputation: 388396

Since the callback to setTimeout() is executed separate from the main thread, the execution context of the callback will be different so this inside the callback does not point the same object as it was outside the setTimeout, in this case the hovered .box element.

One possible solution here is to use the $.proxy() method to pass a custom execution context for the callback method

 $('.box').mouseenter(function(){
    t = setTimeout($.proxy(function(){
        go = true;
        alert($('span',this).text());
    }, this),1000);
 });

Demo: Fiddle

Another solution is to use a closure variable

$('.box').mouseenter(function(){
    var self = this;
    t = setTimeout(function(){
        go = true;
        alert($('span', self ).text());
    },1000);
});

Demo: Fiddle

Upvotes: 12

Lee Meador
Lee Meador

Reputation: 12985

You can just save the value of this somewhere:

$('.box').mouseenter(function(){
    var elem = this;
    t = setTimeout(function(){
        go = true;
        alert($('span', elem).text());
    },1000);
});

The reason you have to do this is that 'this' gets a new value pretty much whenever a new function gets called. So when the timer stuff calls your inner function, 'this' isn't the same as it is when the mouse stuff calls your outer function.

Technically, the 'this' is called the execution context.

What the code above does is creates a variable inside the closure created when the outer function gets called. We store 'this' in that variable, 'elem', and use it later when the timeout occurs.

Upvotes: 4

Related Questions