0

This code is in a KnockoutJS viewmodel:

function myViewModel()
{
    this.prop1 = ko.observable(123);
    this.prop2 = ko.observable("Hello");
    ..
    ..
}

myViewModel.prototype.func1 = function()
    {
  alert(this.prop1());             //works fine here

        myTimer = setTimeout(function()
        {
            alert(this.prop1());   //this.prop1() raises an undefined error
        }, 3000);                  //from console: Uncaught TypeError: undefined is not a function  
};

Why is the property not recognized within the timer callback? Looks like a scope issue, but I can't seem to solve it.

iSofia
  • 962
  • 1
  • 11
  • 27

1 Answers1

2

You should read about Javascript scopes and the var self = this idiom. The this keyword can behave unexpectedly in callback functions, as it may be set to something unexpected (like the function calling the timeout callback, or window, or...).

Something like* this will be an immediate solution to your problem:

myViewModel.prototype.func1 = function()
{
    var self = this;
    alert(self.prop1());             //works fine here

    myTimer = setTimeout(function() {
        alert(self.prop1());
    }, 3000);                
};

* "like" this, because your question does not have code to actually reproduce your problem; a repro would be much more useful in helping you solve a problem

Community
  • 1
  • 1
Jeroen
  • 53,290
  • 30
  • 172
  • 279
  • Hello Jeroen, and thanks a million; that did it. You did advise me to read up on JavaScript scopes in another post, but regretfully, I did not. I never quite understood the self keyword. Thank you very much. – iSofia Oct 28 '14 at 08:09
  • Glad it helped. Even if you don't have time to read up on it (it's a dense topic), just remember to always start your view model constructor functions with `var self = this;` and use `self` instead of `this` everywhere, and you'll be spared a whole slew of problems. – Jeroen Oct 28 '14 at 08:14
  • I'll be sure to do that. Thank you for the tip, and for the solution. You're a life saver, Jeroen. – iSofia Oct 28 '14 at 08:39
  • 1
    @iSofia Just in the interests of education - the problem here is that a setTimeout call will always be in the context of window (meaning `Boolean(window === this)` evaluates to true). There are ways to fix this but since you are still fairly new to javascript I won't confuse you with them. You are better off using `var self = this` as @Jeroen suggested. – Samih Oct 28 '14 at 14:42
  • +1 @Samih, feel free to slipstream your comment into the answer. – Jeroen Oct 28 '14 at 15:01