Tag Archives: Jquery

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.

Updating to jQuery 1.9

Background on why I was Updating to jQuery 1.9:  For a number of reasons, I needed to update my website to a newer version of jQuery, jQuery 1.9. My site, designed in 2010 was started on v1.4 and had last been updated to 1.7 in 2011. I knew I had several out-of-date methods and expected to some debugging and troubleshooting. Well, in the end, it took me 6 hours spread over two days. It wasn’t really that bad, but since I don’t upgrade jQuery everyday, I had a little re-learning to go through.

For starters, I knew that v1.9 had deprecated many of its old methods. In fact, I learned from the upgrade web page, , that v1.9 comes with a special migration plug-in. I was pleased to see this and used this to address most all of my updating challenages.

For example, $.browser() method was deprecated. The migrate script reported this to me in the Chrome console, as follows:

Chrome console:

With a little digging, I was able to find that I was using an old version of blockUI. When I changed to the new version the warning message went away.

I also got the following warning messages related to type changing and the change to the andSelf() method:

Chrome console:

Again, it took a lot of digging, but I was able to isolate the problem to my tmpl.js script. I was using a really old version. I think with a little more skill on my part, I would better be able to use stack backtraces or some other Chrome tool to find these quicker, but this problem was hard for me to find.

Since I was also using an old version of jQuery-UI, I stumbled upon a couple of breakages triggered by curCSS:

Chrome console:

For some reason, also, the dialog() method wouldn’t display text in the “OK” button and it would always popup at 0.0 (upper left), so I upgraded to jQuery-ui v1.9.2.

One last thing for Updating to jQuery 1.9. I had to change all of my .live() events to .on(). The migration guide clearly covered this.

Here’s an example from my website:

//$('#journal input').live('keydown', function(evt) {
$(document).on('keydown','#journal input', function(evt) {

This was easy to do; I had to do it in 6 different place, and it worked the first time.

Updating to jQuery 1.9 was a little more painful than I would like, but feels good to get caught up.

Ok, now that I’ve converted to jQuery v1.9, I can try out some of the new things.

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 */