How to use “setTimeout” to invoke object itself

How to use “setTimeout” to invoke object itself

Why can’t I use setTimeout in a javascript object?
Message = function () {


this.messageFactory = …
this.feedbackTag = document.getElementById(‘feedbackMessages’);

this.addInfo = function (message) {
var info = this.messageFactory.createInfo(message); // create a div
this.feedbackTag.appendChild(info);

setTimeout(‘this.feedbackTag.removeChild(info)’, 5000);
// why in here, it complain this.feedbacktag is undefined ??????

};
}

Thanks for Steve`s Solution, now it will work if the code is as below…
because the ‘this’ before was actually pointing to the function within setTimeOut, it cannot rearch Message.
Message = function () {


this.messageFactory = …
this.feedbackTag = document.getElementById(‘feedbackMessages’);

this.addInfo = function (message) {
var info = this.messageFactory.createInfo(message); // create a div
this.feedbackTag.appendChild(info);

var _this = this;
setTimeout(function() { _this.feedbackTag.removeChild(info); }, 5000);

};
}

But why doesn`t it work if we do this:
Message = function () {


this.messageFactory = …
this.feedbackTag = document.getElementById(‘feedbackMessages’);
// public function
this.addInfo = function (message) {
var info = this.messageFactory.createInfo(message); // create a div
this.feedbackTag.appendChild(info);

delayRemove(info);

};
// private function
function delayRemove(obj) {
var _this = this;
setTimeout(function() { _this.feedbackTag.removeChild(info); }, 5000);
}
}

Related:  What is stateful filtering in AngularJS?

Solutions/Answers:

Solution 1:

Try replacing this line:

setTimeout('this.feedbackTag.removeChild(info)', 5000);

with these two lines:

var _this = this;
setTimeout(function() { _this.feedbackTag.removeChild(info); }, 5000);

Note:

Never pass setTimeout a string, as this invokes eval (which you should only use when necessary). Instead, pass setTimeout a function reference (this can be an anonymous function).

Finally, always check that the this keyword is pointing to what you think it points to (see http://www.alistapart.com/articles/getoutbindingsituations).

Addressing Question 2:

I believe that for normal functions, this is set to the window object—regardless of where they are declared. So moving the code into a separate function wouldn’t fix the problem.

Solution 2:

A neater way is to just pass this as an argument to the function being called in the timeout:

function delayRemove(obj) {
  setTimeout(function(_this) {
      _this.feedbackTag.removeChild(obj);
    }, 5000, this);
}

You should really pass obj as an argument as well, just to make sure it is in scope (the number of parameters is unlimited):

function delayRemove(obj) {
  setTimeout(function(_this, removeObj) {
      _this.feedbackTag.removeChild(removeObj);
    }, 5000, this, obj);
}

HTML5 and Node.js extended the setTimeout function to accept parameters which are passed to your callback function. It has the following method signature.

Related:  Unknown provider: $modalProvider <- $modal error with AngularJS

setTimeout(callback, delay, [param1, param2, ...])

As setTimeout isn’t actually a JavaScript feature your results may vary across browsers. I couldn’t find any concrete details of support, however as I said this is in the HTML5 spec.

Solution 3:

To answer your last question: “Why doesn`t it work if we do this”:

Message = function () {

...
...        

this.messageFactory = ...
this.feedbackTag = document.getElementById('feedbackMessages');
// public function
this.addInfo = function (message) {
    var info = this.messageFactory.createInfo(message); // create a div
    this.feedbackTag.appendChild(info);

    delayRemove(info);

};
// private function
function delayRemove(obj) {
    var _this = this;
    setTimeout(function() { _this.feedbackTag.removeChild(info); }, 5000);
}}

It’s not working because you are passing an undefined variable (info) instead of a defined variable (obj). Here is the corrected function:

function delayRemove(obj) {
var _this = this;
setTimeout(function() { _this.feedbackTag.removeChild(obj); }, 5000);}

References