0

I have a javascript 'class' which contains a wrapper method to call jquery .ajax(). I want to pass in the onSuccess and onError function handlers, but am not sure how. I can do this with plain old global functions, but I'm trying to improve my javascript (from Java background). Any pointers would be appreciated.

In the _makeAjaxCall() method below, how do I reference the onSuccessHandler

function testApp() {
  new X();
}

function X() {
  // Init X by making Ajax call, passing the func to be called on ajax return
  this._makeAjaxCall(initUrl, this.onSuccessInit, this.onError);
  // Make another ajax call to init another component
  this._makeAjaxCall(initUrl, this.onSuccessSomeOtherAjaxCall, this.onError);
}

X.prototype.onSuccessInit = function(){
  this.doStuff(...);
}

X.prototype.onSuccessSomeOtherAjaxCall = function(){
  this.doOtherStuff(...);
}


/**
 * make an ajax call, and call the provided success/error handler
 */
X.prototype._makeAjaxCall = function(url, onSuccessHandler, onError){
  $.ajax({
    url : url,    
    success : function (jsonData, textStatus, XMLHttpRequest) {
      // If I don't user 'this', the func called but I've lost my reference
      // to my instance of X
      onSuccessHandler();

      // If  I use 'this', it points to the ajax call object, not to my X object.
      this.onSuccessHandler();

    }
  });
}

3 Answers 3

1

The problem is that when the success callback is called by the $.ajax function, the default context is used window. You need to tell JQuery that you want a different context, so you can do one of 3 things:

Add a context attribute to the hash that is sent to $.ajax, so I your case you can do:

$.ajax({
   url: url,
   context: this, // this will tell JQuery to use the right context
   success: this.onSuccessHandler
});

Use JQuery's $.proxy function, like:

$.ajax({
    url: url,
    success: $.proxy(this.onSuccessHandler, this) // this will bind the correct context to the callback function
});

Cache the variable this, like @mVChr suggested, although I would encourage you to use self as it has become somewhat of a javascript idiom

 var self = this;
 $.ajax({
     url: url,
     success: function(data) {
         self.onSuccessHandler(data);
     }
 });

Edit:

If you need a more in depth explanation of context and scope in javascript checkout this article: http://www.digital-web.com/articles/scope_in_javascript/

Sign up to request clarification or add additional context in comments.

4 Comments

Hi - thanks for the response - solution #1 doesn't work, I get Object #<X> has no method 'onSuccessHandler', solution #2 fails silently and solution #3 doesn't work for me because I have multiple success handlers I pass in to the ajax wrapper. I have updated the question to clarify the way I need to be able to call the ajax wrapper method - it is used from multiple methods and I have multiple success handler methods. Perhaps this isn't doable in javascript and I need to refactor...
It worked for me by just adding the context: this attribute to the $.ajax, see call jsfiddle.net/bX35E BTW, in _makeAjaxCall you are calling .ajax instead of $.ajax.
Hi - still not it because I don't have the context of my instance in the success handlers. I've updated your script : jsfiddle.net/bX35E/2 - See the instance variable is undefined when the success handlers are called.
Fron de jsfiddle, you don't really need this construct return function() { alert("onSuccessSomeOtherAjaxCall, _instanceVariable="+self._instanceVariable); } You can access the this variable in the handlers directly since it will be set correctly by the call to $.ajax with context: this
0

Cache this within the local scope of _makeAjaxCall before conducting the ajax call:

X.prototype._makeAjaxCall = function(url, onSuccessHandler, onError){
  var _X = this; // cache this

  $.ajax({
    url : url,    
    success : function (jsonData, textStatus, XMLHttpRequest) {
      // use cached this
      _X.onSuccessHandler();
    }
  });
}

Comments

0

Thanks to input from CarlosZ & mVChr, I've figured out the solution, http://jsfiddle.net/bX35E/3/

$(document).ready(function testApp() {
  new X();
});

function X() {
  console.dir(this);
  var initUrl = "/echo/json/";
  this._instanceVariable = "I AM defined!";
  // Init X by making Ajax call, passing the func to be called on ajax return
  this._makeAjaxCall(initUrl, this.onSuccessInit(), this.onError);
  // Make another ajax call to init another component
  this._makeAjaxCall(initUrl, this.onSuccessSomeOtherAjaxCall(), this.onError);
}

X.prototype.onSuccessInit = function(){
  //this.doStuff(...);
    var self = this;
    return function() {
       alert("onSuccessInit, _instanceVariable="+self._instanceVariable);
    }
}

X.prototype.onSuccessSomeOtherAjaxCall = function(){
    var self = this;
    return function() {
      alert("onSuccessSomeOtherAjaxCall, _instanceVariable="+self._instanceVariable);
    }    
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.