Ajax Request Return

A question that comes up frequently on the discussion group is, in essence, "Why isn't my onSuccess handler returning a value?"

Consider this code:

function showRecord(target, recid)
{
    var record;
 
    new Ajax.Request("getrecord.php", {
        parameters: {
            id: recid
        },
        onSuccess: function(response) {
 
            record = response.responseJSON.record;
        }
    });
 
    if (!record)
    {
        showError("Record " + recid + " not found");
    }
    else
    {
        target = $('target');
        target.down('.recid').update(record.id);
        target.down('.desc').update(record.description);
        target.down('.status').update(record.status);
    }
}

What the author is trying to do here is load a record from the server based on a record ID (using a page that will return the record in JSON format as the body of the response), and then display it in a target element that has child elements for the record's ID, description, and status.

But what will it actually do? It will always show an error saying the record wasn't found. Typically at this point the author spends a great deal of time trying to debug the getrecord.php file on the server, and pulling out his/her hair. :-)

The problem here is that the author is thinking of the Ajax.Request as a function call, expecting it to run inline (synchronously) with the other code in his/her showRecord function. It isn't, and it doesn't. Ajax.Request initiates the request, but the request runs asynchronously and finishes sometime later, hence the callbacks. (You can make Ajax.Request calls synchronous, but there's usually no good reason to and it locks up the UI of the browser pretty badly.)

The code needs to be refactored so that the result of the call is handled separately from the initiation. We'll also throw in some code handling the possibility that the getrecord.php file could return valid JSON saying the record wasn't found. Something along these lines:

function retrieveRecord(target, recid)
{
    new Ajax.Request("getrecord.php", {
        parameters: {
            id: recid
        },
        onSuccess: function(response) {
 
            if (response.responseJSON.record)
            {
                displayRecord(target, response.responseJSON.record);
            }
            else
            {
                showError("Record #" + recid + " not found");
            }
        },
        onFailure: function(response) {
            showError("Error loading record #" + recid);
        },
        onException: function(request, ex) {
            showError("Exception loading record #" + recid);
        },
    });
}
function displayRecord(record)
{
    target = $('target');
    target.down('.recid').update(record.id);
    target.down('.desc').update(record.description);
    target.down('.status').update(record.status);
}

The retrieveRecord function (note we've changed its name) initiates the retrieval operation and then returns immediately; when the operation is complete, either onSuccess is called and we use displayRecord to display it, or onFailure or onException is called and we display an error.

This code is an example for illustrating the point, not a bulletproof example of doing an Ajax.Request. Check out the bulletproof Ajax request "how to" if you'd like a robust request example.

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License