msfanboy
msfanboy

Reputation: 5291

Refactor jquery ajax call using the promise object

I am doing an async cross domain call with authentication.

When I have authenticated I retrieve the real application data with a generic get method:

define(['jquery'], function ($) {
    return {
        get: function (url, data) {

            // Call to authenticate before retrieve data
            $.ajax({
                type: 'POST',
                url: 'root/authentication',
                data: { user: root: password: root },
                dataType: 'json',
                xhrFields: {
                    withCredentials: true
                },
                complete: function (response) {

                    // Call to retrieve application data
                    $.ajax({
                        beforeSend: function (xhr) {
                            xhr.withCredentials = true;
                        },
                        type: 'GET',
                        url: root + url,
                        xhrFields: {
                            withCredentials: true
                        },
                        async: true,
                        dataType: 'json',
                        crossDomain: true
                    });
                }
            });
        }
    };
});

the above data call is called by another non-generic code:

define(['cors'],
    function(cors) {
        return function CustomerService() {            
            function getCustomers() {
                return cors.get('/customers');
            }
            return {
                getCustomers: getCustomers
            };
        };
    })

In my knockoutjs viewmodel I want to do this:

When the asyc call is made execute the renderCustomers function and update the UI.

 $.when(customerService.getCustomers())
            .done(renderCustomers)
            .fail();


        function renderCustomers(customers) {

            // Add data to knockout observables
        }

What do I have to change that I get my customers into the renderCustomers function?

Right now customers is undefined and I guess thats because my ajax call is not correctly setup for the promise.

Upvotes: 0

Views: 568

Answers (1)

Thinking Sites
Thinking Sites

Reputation: 3542

In your first snippet, your Ajax call does not do anything with the customer data on success. Try this:

define(['jquery'], function ($) {
    return {
        get: function (url, data) {
                var result = $.Deferred();  // create a deferred object to return
            $.ajax({
                type: "POST",
                url: 'root/authentication',   // you had a typo here
                data: { user: root: password: root },
                dataType: 'json',
                xhrFields: {
                    withCredentials: true
                },
                complete: function (response) {
                    // Call to retrieve application data
                    $.ajax({
                        beforeSend: function (xhr) {
                            xhr.withCredentials = true;
                        },
                        type: "GET",
                        url: root + url,
                        xhrFields: {
                            withCredentials: true
                        },
                        async: true,
                        dataType: 'json',
                        crossDomain: true
                    }).done(function(responseData){
                            // resolve the manually created deferred object, and send it the customer data
                        result.resolve(responseData);
                    });
                }
            });
            return result; // return your deferred object
        }
    };
});

Note that calling 'done' on ajax is the same as calling 'success.' By returning the Deferred, you'll be able to use cors.getCustomers() as a deferred itself.

You can refactor your final snippet to remove the 'when' call and use the deferred from getCustomers directly and bind your knockout there:

customerService
    .getCustomers()  // this returns an deferred now so you can add done and fail events
  .done(function(customers) {

        // Add data to knockout observables
        var elem = document.getElementById('myelement');
        ko.applyBindings(customers,elem);
    });

Upvotes: 1

Related Questions