I'm calling ParentObject.doSomething() which inturn calls the WebService object to perform some ajax calls, and on success of the ajax call, the callback function is executed. But any parent function inside the callback function fails.
I think this has something to do with scope resolution. I am not able to find a workaround for this problem.
Is there a better architectural style to modularize the ajax services and model?
I've create a jsfiddle also - /
var ParentObject = {
doSomething: function(){
document.write("Inside doSomething <br />");
var self = this;
WebServices.firstService("some URL", self.successCallback);
},
changeData: function(data){
//Manipulate data
document.write("Inside changeData <br />");
},
successCallback: function(jsonData){
document.write("Inside successCallback <br />");
try {
//Execution fails at this point. Possibly because of scope resolution
this.changeData(jsonData);
}
catch (error) {
console.log(error);
document.write(error);
}
},
};
var WebServices = {
firstService: function(url, successCallbackHandler){
document.write("Inside firstService <br />");
//Get data using the URL
//on success call successCallback
successCallbackHandler("some data");
}
};
$(document).ready(function() {
ParentObject.doSomething();
});
I'm calling ParentObject.doSomething() which inturn calls the WebService object to perform some ajax calls, and on success of the ajax call, the callback function is executed. But any parent function inside the callback function fails.
I think this has something to do with scope resolution. I am not able to find a workaround for this problem.
Is there a better architectural style to modularize the ajax services and model?
I've create a jsfiddle also - http://jsfiddle.net/bzKXr/2/
var ParentObject = {
doSomething: function(){
document.write("Inside doSomething <br />");
var self = this;
WebServices.firstService("some URL", self.successCallback);
},
changeData: function(data){
//Manipulate data
document.write("Inside changeData <br />");
},
successCallback: function(jsonData){
document.write("Inside successCallback <br />");
try {
//Execution fails at this point. Possibly because of scope resolution
this.changeData(jsonData);
}
catch (error) {
console.log(error);
document.write(error);
}
},
};
var WebServices = {
firstService: function(url, successCallbackHandler){
document.write("Inside firstService <br />");
//Get data using the URL
//on success call successCallback
successCallbackHandler("some data");
}
};
$(document).ready(function() {
ParentObject.doSomething();
});
Share
Improve this question
asked Jul 24, 2012 at 12:21
Anirudh SAnirudh S
731 silver badge3 bronze badges
5 Answers
Reset to default 11Writing self.successCallback
doesn't bind the function to self
, you have to actually call the function as self.successCallback()
to bind the context correctly.
You can do that easily by wrapping the call in a closure which retains access to self
:
doSomething: function(){
document.write("Inside doSomething <br />");
var self = this;
WebServices.firstService("some URL", function() {
self.successCallback();
});
},
or in ES5 you can use .bind()
which ensures that the this
context for successCallback
is always the specified parameter:
doSomething: function(){
document.write("Inside doSomething <br />");
WebServices.firstService("some URL", this.successCallback.bind(this));
},
Here is the prettiest way to do it:
WebServices.firstService("some URL", this.successCallback.bind( this ));
However, it's not cross-browser. (read: IE8 and below can't use it)
This is why jQuery has $.proxy
:
WebServices.firstService("some URL", $.proxy( this.successCallback, this ));
When the callback function is called, the this
is not valid. In javascript, if a function is called with foo.bar()
, this
will be set to foo
, but if you just call foo()
, the previously set this
will be kept, in your case the element of the event, probably your WebService
.
To avoid this, you must use closures. You can replace this.changeData(jsonData);
by ParentObject.changeData(jsonData);
. Closures means than a function can access variable in the scope where the function was defined, so your function can access ParenObject.
A more elegant way could be:
var ParentObject = {
doSomething: function(){
document.write("Inside doSomething <br />");
var self = this;
WebServices.firstService("some URL", function(jsonData) {
document.write("Inside successCallback <br />");
self.changeData(jsonData);
}
},
changeData: function(data){
//Manipulate data
document.write("Inside changeData <br />");
}
};
You callback function is defined directly in you doSomething
function, so you have access to the variable self
defined in it, and can call self.changeData()
.
Another possiblitity is change
WebServices.firstService("some URL", self.successCallback);
to
WebServices.firstService("some URL", function(data){ return self.successCallback(data) });
The basic problem is that, unlike Python, methods Javascript in Javascript forget about their owner object as soon as you pass them somewhere else or set another variable.
if you change this.changeData(jsonData);
to ParentObject.changeData(jsonData);
it should work.
The reason for the error is that the this
variable no longer refers to ParentObject
when the AJAX call returns.
An alternative approach is to store a reference to this
inside another variable (by convention called that
) and change your code to say that.changeData(jsonData);