noway
noway

Reputation: 2585

Reaching $this value from another function

I had these lines in my javascript file and it was working fine.

handleInput = function(e) {
    var $this = $(this),
    id = $this.attr("id");
    alert(id);
}

....

something.bind("keyup", handleInput);

Then I decided to delay the input function and added following lines:

handleDelayedInput = function(e) {
    setTimeout(handleInput(e), 50);
}

.....

something.bind("keyup", handleDelayedInput);

But now alert(id); says undefined, because I think I couldn't pass the this to that function.

Am I right? How can I fix? Is there any better way to do that?

Upvotes: 0

Views: 78

Answers (4)

FishBasketGordo
FishBasketGordo

Reputation: 23142

Use the apply function:

var handleDelayedInput = function(e) {
    var that = this;
    setTimeout(function() {
        handleInput.apply(that, [e]);
    }, 50);
}

something.bind("keyup", handleDelayedInput); // Assuming something is a 
                                             // jQuery object

Here's a working jsFiddle.

Calling handleInput like this setTimeout(handleInput(e), 50); will lose the context, so this won't be what you expect within handleInput in that case.

Also, setTimeout should be passed a function, not the result of a function (unless the result is itself a function).

Upvotes: 1

Matt Zeunert
Matt Zeunert

Reputation: 16571

When jQuery calls the event handler it sets the context of the handler function. This isn't the case when handleInput is called in your second piece of code, so this is set to the default value window.

You can use apply or call to set the context:

handleInput.call(this, e);

The difference between the two is that apply takes an array of arguments while you can pass the arguments to call one by one: func.apply(context, arg1, arg2).

So your full code would be:

handleInput = function(e) {
    var $this = $(this),
    id = $this.attr("id");
    alert(id);
}

handleDelayedInput = function(e) {
    var element = this;
    setTimeout(function(){
        handleInput.call(element, e);
    }, 50);
}

something.bind("keyup", handleDelayedInput);

Note that, since we're using setTimout we need to find a way to pass the element to the timeout handler function. Also, in your code you're using the return value of handleInput(e) as the handler function - rather than handleInput.

I agree with Mike though, if you wrote handleInput yourself and you can modify it there's not point in using this instead of just passing the argument. If you still want to use handleInput as a direct handler somewhere else it would make sense to keep it the way you have it.

Upvotes: 1

Mike Brant
Mike Brant

Reputation: 71422

That is because you are no longer passing handleInput any object context like you were when calling it from your jQuery bind method. Personally I would rewrite the whole thing like this:

something.on("keyup", function(e) {
    var obj = $(this);
    setTimeout(function(obj) {
        alert(obj.attr("id");
    }, 50);
});

Note the use of on() instead of bind() which is now the preferred usage.

Upvotes: 2

Ridcully
Ridcully

Reputation: 23665

You could do it like so:

handleInput = function(e) {
   var $this = $(this),
   id = $this.attr("id");
   setTimeout(function() {alert(id);}, 50);
}

Upvotes: 0

Related Questions