1024px-Flatirons_Winter_Sunrise_edit_2
This is the second post in a multi-part series on creating a JavaScript component for handling your Ajax requests in front-end development across your enterprise. You can find the first post here:

In the last post we covered some introductory topics for creating your own JavaScript utility library, which wraps functionality for Ajax. We’ll start where we left off. Our first step will be to add a few tweaks to our library to make it more usable:

[js] var mySiteAjax = ( function( $ ) {
return (
function( params ){
var settings = $.extend({
url: "",
spinner: undefined,
dataType: "html",
data: "",
type: "GET",
cache: false,
success: function() { }
}, params );

);
})(jQuery);
[/js]

We’ve done two things to our old example. We’ve added new parameters for type and data that could be passed in. Additionally, we’ve removed a named function and returned an object literal. This enables easier usage:

[js] mySiteAjax({
url: "myUrl",
success: function( data ) {
//do something with the data here
}
});
[/js]

Although a good start, this solution is not yet satisfactory as we are not yet handling errors in any capacity. How do we handle errors and display messages to the user? Additionally showing and hiding of loading notification images is present but not customizable. What if a page doesn’t want to do a simple showing and hiding of load images? How can we decouple the notifications from our Ajax component library?

Handling and Displaying Errors

When dealing with Ajax errors there are typically two concerns – handling the error in code and displaying an error message to the user.

Handling the Ajax Error

A popular technique for “handling” Ajax errors is to either never add an error callback for the Ajax request, or to end up with code like this (including the todo comment):

[js] $.ajax({
//…
error: function() {
// todo: handle error here.
},
//…
});
[/js]

Most of us have been there. It is often a struggle to determine what reasonable actions can be done with an Ajax error. Yet there are some options. A few pragmatic actions we could take upon Ajax error:

  • Try again (especially for GETs).
  • Have debug code for non-production code which logs the error details to the console.
  • Have an error specific Ajax request URL (either global for all sites or specific to your application). This activity is typically a request in which data is sent to the server and the client does not care about the response. This is typically used to log the issue to a server-side resource.
  • Automatically take action based on HTTP Status Code. We can detect certain error codes from the server response and take action. For example a 401 or 403 error may be an indication of expired client credentials. In this case we could redirect the user to a login page to establish new credentials.
  • Suggest to the user next steps as part of the error message.

It would be prudent for our utility library to take some actions based upon HTTP status code. If the user request comes in as unauthorized we will redirect to a new page. If there is a server timeout we will try the Ajax request a second time.

To accomplish this we need to add an error callback function to .ajax(). We are also going to add another programming technique to repeatedly call .ajax(). First the code:

[js] var mySiteAjax = ( function( $ ) {
return (
function( params ) {
//…
var retries = 0;
function ajaxRequest ( ) {
$.ajax({
beforeSend: function(){
$(settings.spinner).show();
},
url: settings.url,
dataType: settings.dataType,
success: settings.success,
complete: function(){
$( settings.spinner ).hide();
},
error: function( xhr, tStatus, err ) {
if( xhr.status === 401 || xhr.status === 403 ) {
//redirect action here
} else if ( xhr.status === 504 && !retries++ ) {
ajaxRequest();
}
} // end error handler
}); // end $.ajax()
}; // end ajaxRequest()
ajaxRequest();
} // end getViaAjax()
); // end return statement
})(jQuery);
[/js]

We’re using the status property of the XmlHttpRequest object to determine the type of error encountered. With our authorization issues we can detect an authorization error status code and redirect to our authorization page. Handling retries requires us to call the original Ajax call again. To do that we can use recursion.

In our case of recursion we are setting up a retries variable to determine the number of Ajax requests we setup. retries is declared outside of the recursive function. We can use and increment the retries variable inside of our function because of lexical scoping. If retries is 0 and a timeout error code occurs, we increment retries and recursively call ajaxRequest. The ajaxRequest function then sets up a another ajax request. If another timeout occurs retries is now set to 1 which will keep another recursive call from happening.

After we’ve created our ajaxRequest function we then execute it to kick off an initial Ajax request.

We’re not using the global event handler, .ajaxError(). This is because we only want our error handling to affect those calls which come through our component. If we attach a handler globally using .ajaxError() then all ajax errors will result in the execution of our callback. While you may want that behavior in your application, it’s generally considered bad practice to introduce code with side effects.

This example gets us started down the path of retries, but isn’t a complete solution. Other good additions would be to allow the number of retries to be specified as a parameters, and to add timers to throttle retries.

Displaying Error Messages to the User

Notifying the user of the error involves interaction with another component on the page (you can find an example of creating such a component with our message center plugin blog posts 1 and 2). We could set up another parameter to be passed as an error callback function. However, it seems like we’re quickly going parameter-happy.

We’re already expecting the calling code of our utility function to know about the load notifications (spinners) that may be on the page. We’d be adding yet another responsibility of the callee to know which and how many messaging components may be on the page and would need to be notified of an Ajax error. This puts pressure on the code calling our Ajax library to be edited every time any messaging or loading notification widgets are added, edited, or removed from the page.

Paradigm Shift – Communicating Between Components with Publish/Subscribe

In our case we have three separate components that are trying to interact on the page:

  • An Ajax system
  • A ‘loading’ notification system
  • A flash message or message center

We need an effective way to communicate between components. In the case of our Ajax library, we need to notify any components that an error message is available to be displayed or that a load notification needs to start or end.

Introducing Publish/Subscribe

A great solution would be to broadcast over a channel that an error occurred or that loading has started. Consumers could register a callback to run when a message was broadcast over a specific channel.

One way to accomplish this is the publish/subscribe pattern. With this pattern a publish function typically exists which broadcasts using a message topic. A subscribe function is used to bind a callback function which will be executed when a message topic is broadcast. Data can be passed to the subscriber through an additional parameter.

If we compare a typical publish/subscribe system to a radio broadcast, the “message topic” would be the selected AM, FM, or Satellite station. The data being passed to the subscriber would be analogous to the audio coming through the radio.

Using Custom jQuery Events for Publish and Subscribe

We can illustrate publishing and subscribing by using jQuery custom events names. We can use the event name as our message topic and pass data using the additional parameters.

Lets add a mechanism to publish error messages as well a standard error message:

[js] var mySiteAjax = ( function( $ ) {
var standardError = "Oops. Sorry about that.";
return (
function( params ) {
var settings = $.extend({
url: ”,
spinner: undefined,
dataType: ‘html’,
cache: false,
success: function(){}
}, params);

); // end return statement
})(jQuery);
[/js]

We’re publishing with a custom event named “ui-flash-message”. The .trigger() method takes in an array of parameters as a second argument. We chose to pass in a single hash (object literal) with our message attached.

Now that we’ve covered publishing, lets take a look at how a subscribe might be set up:

[js] // … somewhere in a component that displays messages
$(document).bind( "ui-flash-message",
function(evt, data) {
if(data.message) {
showMessage(data.message);
}
};
// …
[/js]

Our subscriber must be set up before a message is published. In this case as long as our message component has already been loaded and the above code has been executed, then the component is waiting for a message to be published.

Load Notifications

Our old implementation of load notification was for a selector to be passed in and our Ajax component would handle the showing and hiding of a ‘spinner’. This technique is not ideal. The Ajax component has no business implementing specific behavior for spinners (such as using .show() and .hide()). It would be much better to use our publish/subscribe methodology to allow other components to handle the behavior.

[js] // we ‘define’ undefined to alleviate concerns
// that someone may have done something stupid
// like this in code before this code executes:
// undefined = "Im now defined.";
// credit: Ben Alman (see comments)
var mySiteAjax = ( function( $, undefined ) {
return (
function( params ) {

); // end return statement
})(jQuery);
[/js]

Now we can add a load notification component to our application, where we can handle showing and hiding spinners:

[js] // … somewhere in a load component
$(document).bind( "ui-load-start-message",
function(evt, data) {
$(data.spinner).show();
});

$(document).bind( "ui-load-end-message",
function(evt, data) {
$(data.spinner).hide();
});
// …
[/js]

We now have much better separation of concerns. The Ajax component only publishes messages and isn’t concerned with implementation of a loading notification system.

I’ve set an example of this solution on a jsFiddle with a few use cases. Take a look at the example and feel free to play with the functionality on your own. Post in the comments if you find anything interesting!

Although you can create a message bus with jQuery custom events, there’s overhead and DOM interaction that isn’t necessary. Components exist today that allow for publish/subscribe to occur using only JavaScript. I encourage you to look for those components and use them for publish and subscribe interactions.

PostScript / Errata :
There have been some good comments below, so we’ve made a few changes:

  • The last full Ajax solution has been updated with suggestions and appropriate credit given.
  • The jsFiddle has been updated to reflect those changes.
  • Rebecca Murphey correctly pointed out that we are adding a variable to the global scope and that is something that should be minimized. A good approach would be to create a simple namespace (object) and add this utility library to that namespace. So the assignment at the top statement wouldn’t be mySiteAjax, but rather myCompanyNS.siteAjax or something similar. Note that you’ll need to ensure myCompanyNS exists and created an empty object if it does not already. We are still adding to the global scope, but one is better than many possible editions.