1

I want to let an element fade in, and stay on the page for 7 seconds before it fades out. And I can cancel it anytime. I defined the following functions. But when I called info_timeout.setup(ele, 'some msg here'), the ele just faded in and faded out immediately.

Am I missing something?

var info_timeout = {
show_info: function(){
    this.ele.html(this.msg).fadeIn('normal');
    this.id = setTimeout(this.hide_info(), 7000);
},
hide_info: function(){
    console.log(this.ele, this.id);
    this.ele.fadeOut('slow');
    delete this.id;
},
setup: function(ele, msg) {
    this.ele = ele;
    this.msg = msg;
    this.cancel();
    this.show_info();
},
cancel: function() {
    if(typeof this.timeoutID == "number") {
        clearTimeout(this.id);
        delete this.id;
    }
}

};

Thanks.

braX
  • 11,506
  • 5
  • 20
  • 33
Jensen
  • 1,653
  • 4
  • 26
  • 42
  • this is asked a hundred times a day. – zzzzBov Dec 11 '11 at 07:14
  • 1
    @zzzzBov Find dup. for a close. Most of the time I think it's just the horrid titles... –  Dec 11 '11 at 07:17
  • @pst, i completely agree about the titles, it's nearly impossible to find dupes of some questions because they're different code with the same issue, and the same answer. – zzzzBov Dec 11 '11 at 09:51
  • http://stackoverflow.com/questions/2037203/why-is-my-function-call-that-should-be-scheduled-by-settimeout-executed-immediat , http://stackoverflow.com/questions/4120781/settimeout-ignores-timeout-fires-immediately –  Dec 11 '11 at 10:33

1 Answers1

5

Several problems.

This invokes hide_info right away. Parenthesis invoke a function-object! (or are used for applying precedence to expressions).

That is,

this.id = setTimeout(this.hide_info(), 7000);

Is [mostly] equivalent to:

var temp = this.hide_info()       // call function ... uh, what?
this.id = setTimeout(temp, 7000)  // temp is "return" value ("undefined" here)

Oops! That's not right :) So take away the parenthesis. This will pass the function-object itself to the setTimeout. (Yes, functions are just objects in JavaScript. The expression this.hide_info is first evaluated to a function-object and, if there is a (...) after, it will invoke said function-object.)

this.id = setTimeout(this.hide_info, 7000)

However, it is still not correct because this inside the timeout function (hide_info) will be wrong! But this can be fixed with using a closure. (There are many great SO answers on the topic, feel free to search!)

var self = this
this.id = setTimeout(function () {
    // now in hide_info "this" will be "self", which was "this" ... outside :)
    self.hide_info()
}, 7000) 

(Or use Function.bind from ECMAScript ed5 or a library.)

Additionally, this.id is not the same as this.timeoutID, and is suspect for "correctness".

Keep it simple. It's okay to pass undefined/0 to clearTimeout: it'll silently ignore you.

cancel : function () {
    clearTimeout(this.id)  // but id is a horrid overloaded name :)
    this.id = undefined
}

Happy coding.