Tag Archives: $.ajax

jqueryWriteLessDoMore120213

$.ajax logging using Ajax Global Events. Re-factoring Single Page Web Application

Background on $.ajax logging using Ajax Global Events:  So I’ve moved from jQuery 1.4 to 1.9. I have some time to refactor my code to take advantage of some of the new features of 1.9 and to get ready for 1.10; the next jQuery release removes some of the deprecated methods.

For this round of coding, I am focusing on the $.ajax() method. In my present design, my single page web application makes REST calls for many of the UI menu items. For example, a click on the FILE->LOAD menu item triggers a function call to code that retrieves a file from my server. The basic pattern is like this:

// Start spinner
// start logging timer
$.ajax({"url":RestURI,
 "type":"GET",
 "dataType":"json",
 success: function(data) {
 // Do success stuff (parse, format and display)
 // stop logging timer, do logging
 // stop spinnger
 }, /* end success: */

 error: function (req, stat, err) {
 // Do error stuff
 // stop logging timer, do logging
 // stop spinner
 } /* end error: */
});

I have more than 7 code blocks that follow this pattern. Since the success/error/complete callback functions have been deprecated and I need to touch the code anyways, I thought I’d use the newish $.ajax() global events handlers  to clean up my code. The event handlers seem to be a useful place to put common pieces of code that really shouldn’t have been so liberally cut-and-pasted when I wrote the original code.

jQueryIcon120213For each of my ajax code blocks, I put a generous amount of logging in. Maybe this logging should only be needed when writing/debugging the code, but for me, since I spend so little dedicated time on this application, I wanted to keep verbose logging on always to make it real easy for me to debug.

$.ajax logging using Ajax Global Events

The following new block of code is doing my $.ajax logging using Ajax Global Events.

$(document).ajaxSend(function(evt, xhr, settings) {
 console.log(settings.type+" "+settings.url+" Sent");
 start = new Date().getTime();
 // Other logging
});
$(document).ajaxSuccess(function(evt, xhr, settings) {
 console.log(settings.type+" "+settings.url+" Success");
 // Other logging
});
$(document).ajaxError(function(evt, xhr, settings, exc) {
 console.log( settings.type+" "+settings.url+" Failed. "
 +xhr.status+"-"+xhr.statusText);
 // Other logging
});
$(document).ajaxComplete(function(evt, xhr, settings) {
 console.log(settings.type+" "+settings.url+" Complete");
 end = new Date().getTime();
 diff = end - start;
 // Other logging
});

As you can see, the ajaxSend/ajaxSuccess/ajaxError/ajaxComplete events are fired in sequence at the $.ajax() function executes and after the  .done(), .fail() and .compete() callbacks are executed.

The “Other logging” comment represents 2 or 3 lines of code where I put logging information into a user visible menu item (REPORTS->LOG) where I can see even more details without having to open the console window. For me, this effort is a nice clean out some of the logging stuff, to make the application logic a little more visible;  this clears up a bunch of clutter for me.

New-ish .done/.fail/.always Callbacks

Therefore, my $.ajax() code blocks are straighten out to follow the new done/fail/always callbacks. Here’s an example new $.ajax() code block:

// Start spinner
$.ajax({url:RestURI,
 type:"GET",
 dataType:"json"})
 .done( function(data, textStatus, jqXHR) {
 // Do success stuff
 }) /* end done: */

 .fail( function (jqXHR, textStatus, err) {
 // Do error stuff
 }) /* end fail */

 .always( function() {
 // stop spinner
 }); /* End always */

Some things to note: I still put the start/stop spinner function calls inline. I may move this to the global even handlers, but not yet.

Deferred Objects

Also, the done/fail/always call backs follow the new Deferred Object model. This will then let me setup some promise objects to let me address some of the async race conditions I have in my application.

For example, I have a case where I can run FILE->SAVE and then run REPORT->General and the report will produce results before the save was completed. I know how to fix this, but I was looking to use my new ajax code blocks architecture to get some practice with promise objects instead… for next time.

Jquery ajax always parameters order inconsistent

My single page web application makes several REST style calls to my server.  Jquery $.ajax is the tool of choice for implementing this on the browser-side.  When converting from Jquery version 1.4 to 1.7+ I started to follow a their new coding pattern.  Here’s the old way, the new pattern and a little gotcha (the jquery ajax always parameters are inconsistent depending on success condition) that I write-up here for my reference and potentially the benefit of others.

Old mode of operation using jquery 1.4 $.ajax syntax:

$.ajax({"url":RestURI,
	"type":"GET",
	"dataType":"text",
	success: function(data) {
		// Do success stuff
		// stop logging timer, do logging
		// stop spinnger            
	}, /* end success: */
	
	error: function (req, stat, err) {    
		// Do error stuff        
		// stop logging timer, do logging
		// stop spinner
	} /* end error: */
});

New pattern using jquery 1.7 uses the chainable done(), fail(), and always() Promise methods derived from the  jQuery Deferred object. .See  code snippet below for the general case for how I use it.  It’s pretty straight forward.

// Start spinner
// start logging timer	 
$.ajax({"url":RestURI,
	"type":"GET",
	"dataType":"text"})
	.done( function(data, textStatus, jqXHR) {
		// Do success stuff
	}) /* end done: */
	
	.fail( function (jqXHR, textStatus, err) {
		// Do error stuff    
	}) /* end fail */
	
	.always( function() {
		// stop logging timer, do logging
		// stop spinner
	}); /* End always */

The new $.ajax pattern lets me have multiple always, done and fails; so I thought it would be good to add a .always at the top — something I would run first before a done or fail. Well, I discovered that the ajax always parameters are inconsistent; that is, the always function returns two different sets of parameters depending on how the $.ajax function returned. If the ajax function failed, then the always callback parameters were (jqXHR, textStatus, err ); if the ajax function was successful, the always callback parameters were flipped: (err, textStatus, jqXHR ).

So if you want to use the always function, then I recommend you setup a callback with no parameters or you do a test of the textStatus parameter — “success” This quirk got me a couple of times. I found references to it on the jQuery bug list — this behavior is by design. The code snippet below captures the issue.  This is not a show stopper; the new promise paradigm is pretty cool and I have some cases where I am chaining together multiple ajax calls, where this will come in really handy.

// Start spinner
// start logging timer	 
$.ajax({"url":RestURI,
	"type":"GET",
	"dataType":"text"})
	.always( function(arg1, textStatus, arg3 ) {
		// on fail: always( function(jqXHR, textStatus, err ) { and textStatus != "success"
		// on done: always( function(err, textStatus, jqXHR ) { and textStatus == "success"
		console.log("First Always function. textStatus="+textStatus+"\n");
	}) /* end always (top) */
	
	.done( function(data, textStatus, jqXHR) {
		// Do success stuff
	}) /* end done: */
	
	.fail( function (jqXHR, textStatus, err) {
		// Do error stuff    
	}) /* end fail */
	
	.always( function() {
		// stop logging timer, do logging
		// stop spinner
	}); /* End always */