Not understanding reference of this with jquery ajax success callback

When making an ajax call with JQuery, the reference of the keyword this changes in the success callback.
In the callback function, all properties are undefined, this._ApiSrc, …
In order to access them I made a var pThis = this; before the $.ajax as those var remains defined in the success callback. This gave me a way to push object in _quotesSetIds within the callback function. Is this right?

Give the following code:

function quote(){
    
    //Private
    this._ApiSrc = "";
    this._queryLimit = 30;
    this._quotesSet = [];
    this._quotesSetIds = [];

    
    //Methods

    this.GetQuote = function (){
        /* Get a new random quotes */
        this._GetQuotesSet();
    };

    this._GetQuotesSet = function(){
        
        var pThis = this; //Give access path to current this.
        //get a set of random quotes.
        $.ajax({
            url: this.GetApi(),
            contentType: "application/jsonp",
            data: "action=query&list=random&format=json&rnnamespace=0&prop=info&rnlimit="+this.GetQueryLimit(),
            dataType: 'jsonp',
            type: 'GET',
            success: function(data) {
                /* Push each object return to quotesSet */
                for (var x = 0; x < data.query.random.length; x++){
                  **_>>>> HERE <<<<_**  pThis._quotesSetIds.push(data.query.random[x]);
                }
            }
        });
    }


    this.SetApi = function(src){
        /* Set the Api source */
        this._ApiSrc = src
    }

    this.GetApi = function(){
        /* Get the Api source */
        return this._ApiSrc;
    }
    
};

var myQuote = new quote();
myQuote.SetApi("https://en.wikiquote.org/w/api.php");
myQuote.GetQuote();

That’s one way of doing it, and it is valid, but there’s an easier way. For “private” properties and methods, don’t use this at all and return an object with only the methods you want to be the public API. It would look something like this code (which may or may not work as is):

function quote(){

    //Private
    _ApiSrc = "";
    _queryLimit = 30;
    _quotesSet = [];
    _quotesSetIds = [];


    //Methods

    GetQuote = function (){
        /* Get a new random quotes */
        _GetQuotesSet();
    };

    _GetQuotesSet = function(){

        //get a set of random quotes.
        $.ajax({
            url: _ApiSrc, //Getter functions are for a public API, not internal use
            contentType: "application/jsonp",
            data: "action=query&list=random&format=json&rnnamespace=0&prop=info&rnlimit="+GetQueryLimit(),
            dataType: 'jsonp',
            type: 'GET',
            success: function(data) {
                /* Push each object return to quotesSet */
                for (var x = 0; x < data.query.random.length; x++){
                   _quotesSetIds.push(data.query.random[x]); //No need for 'this'
                }
            }
        });
    }


    SetApi = function(src){
        /* Set the Api source */
        _ApiSrc = src
    }

    GetApi = function(){
        /* Get the Api source */
        return _ApiSrc;
    }

    return {
        setApi: SetApi,  //Return only what you want to use
        getApi: GetApi,  //Everything else is "private"
        getQuote: getQuote
    }

};

var myQuote = quote();  // No need for the 'new' keyword
myQuote.SetApi("https://en.wikiquote.org/w/api.php");
myQuote.GetQuote();

There are a few other ways I would streamline this, and with code this generalized you’ll want to be careful with what you’re doing in the success callback.

1 Like