Search code examples
ajaxjquerysammy.js

Asynchronously populate Sammy.Storage cache


I'm having difficulty accessing requestJSON on a jQuery $.ajax object outside of the success callback. If I do:

var ajax_request = $.ajax({
    dataType: 'json',
    contentType: 'application/json'
});

console.log(ajax_request.responseJSON);

// this results in `undefined`

How can I access the responseJSON without adding a .success() callback? If I inspect ajax_request in Firebug, I can see the responseJSON property, and the data I expect, but I can't access it via:

ajax_request.responseJSON

More specifically, I'm building an SPA using Sammy and Knockout. In some routes, I need to be able to get JSON from cache, and if it doesn't exist, get the value from a service call and then set it into cache:

var cached_json = storage.fetch('cached_json', function() {
    // make service call
    return $.getJSON(url);
});

event_context.render('template.tpl', {'json': cached_json}).appendTo('#my-target');

But, of course, calling storage.fetch doesn't cause the rest of the code to pause until $.getJSON is complete. This is the part I can't quite figure out how to structure.


Solution

  • I ended up solving this by creating a deferred object that gets or creates the value I need:

    function get_or_create_cache(storage, key, service_endpoint) {
        return $.Deferred(function(deferred) {
            var c = storage.get(key);
            if (c === null || c === undefined) {
                $.when(jsonp_service_request(service_endpoint)).done(function(json) {
                    storage.set(key, json);
                    deferred.resolve(json);
                });
            }
            else {
                deferred.resolve(c);
            }
        }).promise();
    }
    

    In this function, storage refers to a Sammy.Storage instance. jsonp_service_request is a local function that returns a jsonp response, taking into account the location.hostname for local development, where I'm pointing to local.json files, or a remote environment, where I'm calling into an actual API. jsonp_service_request returns an $.ajax function.

    Then in my Sammy route, I can do:

    this.get('#/', function(event_context) {
        $.when(get_or_create_cache(storage, 'my-cache-key', 'service-endpoint'))
            .then(function(json) {
                event_context.render('my-template.template', {'value-name': json})
                    .appendTo('#my-target');
            });
    });