Skip to content Skip to sidebar Skip to footer

Making Functions Wait Until AJAX Call Is Complete With JQuery

Im trying to develop a class in JavaScript I can use to access a load of data that is gathered by an AJAX request easily. The only problem is I need to make the members of the clas

Solution 1:

jQuery already handles this for you using deferred objects, unless i'm misunderstanding what you are looking for.

var courses = {
    getCourse: function (id) {
        return $.ajax({url:"getCourse.php",data:{id:id});
    }
};

courses.getCourse("history").done(function(data){
    console.log(data);
});

I know this isn't exactly what you are looking for, I'm hoping it's enough to push you in the right direction. Deferred objects are awesome.


Solution 2:

The following changes allow you to make the AJAX request just once and you can call your function like

courses.getCourse('xyz', function(course){
    // Use course here
});

Here are the changes

var model_courses = (function() {

    // This is what gets returned by the $.ajax call
    var xhr;
    var _storage = {}; // Used for storing course related info
    _storage.courses = {}; // Used for accessing courses directly
    _storage.references = []; // Stores all available course IDs

    var cls = function () {
        xhr = $.ajax({
            type: "GET",
            url: "data/courses.xml",
            dataType: "xml",
            success: function(xml) {
                $(xml).find("course").each(function() {

                    _storage.courses[$(this).attr('id')] = {
                        title       : $(this).find('title').text(),
                        description : $(this).find('description').text(),
                        points      : $(this).find('points').text()
                    }
                    _storage.references.push($(this).attr('id'))

                });
            }
        });
    }
    cls.prototype = {
            // Made changes here, you'd have to make the same 
            // changes to getCourses and getReferences
            getCourse: function (courseID, callback) {
                if (xhr.readyState == 4) {
                     callback(_storage.courses[courseID]);
                }
                else {
                   xhr.done(function(){
                      callback(_storage.courses[courseID]);
                   })
                }

            },
            getCourses: function () {
                return _storage.courses
            },
            getReferences: function (),
                return _storage.references
            }

    }
    return cls
})()

As a side note, your module pattern will not work very well if you need to instantiate two of these model_courses objects, since the storage objects are all shared in your self calling function's closure. You usually don't mix the module pattern with prototypes (returning a constructor from a module), unless you really know what you are doing, that is, the shared closure variables work as static properties of your class.

This is what I would do if I were you (since you really want private variables)

function ModelCourses() {
    var storage = {
      courses: {},
      references: []
    };

    var xhr = $.ajax({
        type: "GET",
        url: "data/courses.xml",
        dataType: "xml",
        success: function(xml) {
            $(xml).find("course").each(function() {   
                storage.courses[$(this).attr('id')] = {
                    title       : $(this).find('title').text(),
                    description : $(this).find('description').text(),
                    points      : $(this).find('points').text()
                }
                storage.references.push($(this).attr('id'))
            })    
        }
    });

    this.getCourse = function(courseId, callback) {
        function getCourse() {
            callback(storage.courses[courseID])
        }
        if (xhr.readyState == 4) {
            getCourse();
        }
        else {
            xhr.done(getCourse);
        }
    };   
}

Solution 3:

in getStorage either add a check to see if there is any data to pilfer (preferred), or make the "actual" method private than publicize it when it has items it can access. (I would recommend the first though otherwise you'll get exceptions about calling a method that doesn't exists on an object).


Solution 4:

You can define a function getData that would perform the ajax request and that would take the getCourse as a callback. The getData could possibly store locally the result of the Ajax call and test the local storage before performing the ajax call.

You could also specify a private member to allow the ajax call to be run only once. You might want to check underscore.js for some handy tool

Here is a short example code :

cls.prototype.getData = function(callback) {
    /*perform ajax call or retrieve data from cache*/
    callback()
}
cls.prototype.getCourse = function(id) {
    this.getData(function() {
        /*do something with the data and the id you passed*/
    }
}

Post a Comment for "Making Functions Wait Until AJAX Call Is Complete With JQuery"