maja
maja

Reputation: 18034

Accessing Grandparent's variable

I have an Object with the variable "parentVar", and I want to write the response of an ajax-request into it. Sounds easy, but I'm not able to do this, due to some namespace-troubles.

I wrote a very minimalistic example, which shows the problem.

The ajax-request will be started, when I call the Object's init-Function:

var parentObj = new Parent();
//Do some work (I need some functionality from the object before it can be fully initialized)
alert("Old Value = " + parentObj.parentVar);
parentObj.init(function(){
    alert("New Value = " + parentObj.parentVar);
});

The init-Function calls the Function "load" which performs an Ajax-Request, and returns the received data (in another callback-Function).

function Parent(){
    this.parentVar = "old";                 //this value should be replaced

    this.init = function(initCallBack){

        this.load(function(newData){        //load the content of the file
            this.parentVar = newData;       //write the content into the variable
            initCallBack();                 //I'm done!
        });

    }

    this.load = function(callbackFunc){
        //load the new value from a file via ajax (asyncron).
        //When finished: call callbackFunc
        callbackFunc("newValue");
    }
}

I already tried passing the scope to the loader-function, and getting it back in the callBack-Function. But it didn't work.

I also tried "var parentscope = this;" in the init-Function, and "parentscope.parentVar = newData;" - it didn't work either.

Is it possible to achieve this with parentVar being private? (I mean "var parentVar = 'old';" instead of "this.parentVar = 'old';").

Upvotes: 3

Views: 591

Answers (2)

nnnnnn
nnnnnn

Reputation: 150020

The callback function passed to load() doesn't have the value of this that you want. The way you call that function this will be window. You can bind the value of this as follows:

    this.load(function(newData){        //load the content of the file
        this.parentVar = newData;       //write the content into the variable
        initCallBack();                 //I'm done!
    }.bind(this));

...and then it will work: http://jsfiddle.net/v9Hvb/

Is it possible to achieve this with parentVar being private? (I mean var parentVar = 'old'; instead of this.parentVar = 'old';).

You can use a private variable inside the Parent() constructor and it will be accessible within all of the methods defined inside the constructor. But it won't be accessible outside with parentObj.parentVar so you'd have to add a getter method.

It would be easier to use a private var self = this; variable inside the Parent() constructor and then use self instead of this in the methods:

function Parent(){
    var self = this;
    self.parentVar = "old";                 //this value should be replaced
    self.init = function(initCallBack){    
        self.load(function(newData){        //load the content of the file
            self.parentVar = newData;       //write the content into the variable
            initCallBack();                 //I'm done!
        });

    }    
    self.load = function(callbackFunc){
        //load the new value from a file via ajax (asyncron).
        //When finished: call callbackFunc
        callbackFunc("newValue");
    }
}

Demo: http://jsfiddle.net/v9Hvb/1/

Further reading: MDN's this article

Upvotes: 1

Chandranshu
Chandranshu

Reputation: 3669

The problem is that the this within the callback passed to the load within the init function doesn't refer to the Parent object but the window object. There is a well known hack for this: save the reference to the Parent's this in _this. Other variable names commonly used are that and self and all these prefixed with more underscores. Here is a code that works:

function Parent(){
    this.parentVar = "old";                 //this value should be replaced
    var _this = this;
    this.init = function(initCallBack){

        this.load(function(newData){        //load the content of the file
            _this.parentVar = newData;       //write the content into the variable
            initCallBack();                 //I'm done!
        });

    }

    this.load = function(callbackFunc){
        //load the new value from a file via ajax (asyncron).
        //When finished: call callbackFunc
        callbackFunc("newValue");
    }
}

Upvotes: 1

Related Questions