Over the weekend I was fiddling was some code to see how to make a generic activity indicator for Ajax requests. I'm sure most of you have seen these but if not, here's one similar to what Facebook uses:

<a href="http://blog.reybango.com/wp-content/uploads/2010/07/facebook.gif"><img src="http://blog.reybango.com/wp-content/uploads/2010/07/facebook.gif" alt="" title="facebook" width="16" height="11" class="alignright size-full wp-image-948" /></a>

While it's may not look like much, that animated .gif is pretty important because it tells a user that something is happening and that results will appear shortly. The last thing you want is for a user to think the page has locked up or broken and using this simple method advises them that their request is being processed.

<h2>Targeted Indicators</h2>

In my case, I was looking for a way to set an indicator within the specific DOM element that would be affected by the XHR call. So if my XHR call was to set the contents of a specific DIV, I wanted the indicator to render within that specific DIV only (similar to what Facebook does). 

First, I created three DIVs and 3 anchor tags:

[code lang="html"]
&lt;a href=&quot;#&quot;&gt;Box 1&lt;/a&gt;|&lt;a href=&quot;#&quot;&gt;Box 2&lt;/a&gt;|&lt;a href=&quot;#&quot;&gt;Box 3&lt;/a&gt; 

&lt;br /&gt;&lt;br /&gt;

&lt;div id=&quot;box1&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div id=&quot;box2&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div id=&quot;box3&quot;&gt;&amp;nbsp;&lt;/div&gt;
[/code]

and I set the DIVs to a specific width and floated them left:

[code lang="css"]
#box1, #box2, #box3 { background-color:#E5EECC; border:1px solid #D4D4D4; width: 200px; float:left; };
[/code]

Next, I created a new method called <em>fillBox()</em> that would take the target element's ID and use that to dynamically create a new IMG tag and insert the activity indicator. What I decided to do was leverage jQuery's global Ajax events to create the generic handlers for this. Using <em>ajaxStart()</em>, which fires off when an Ajax request is initiated, I dynamically create the tag for my activity indicator and inset it using the <em>prepend()</em> method:

[code lang="js"]
		$(ele).ajaxStart( function() {
		
			$(this).prepend( &quot;&lt;img id='throbber' src='facebook.gif' /&gt;&quot; );
		
		})
[/code]

Then using the Ajax global event handler ajaxStop(), I would easily delete the indicator once the Ajax request was done by using the <em>remove()</em> method to delete the IMG tag from the DOM:

[code lang="js"]
ajaxStop( function() {
		
	$(&quot;#throbber&quot;).remove();
		
});
[/code]

Lastly, using some event delegation, I created an event handler for the clicks on the anchor tags:

[code lang="js"]
$( &quot;a&quot; ).click( function(e) {
			
			var el = '';
			switch(e.target.text) {
				case &quot;Box 1&quot;: 
					el = '#box1';
					break;					
				case &quot;Box 2&quot;: 
					el = '#box2';
					break;								
				case &quot;Box 3&quot;: 
					el = '#box3';
					break;										
			} 

			fillBox( el );
			
		});
[/code]

The handler simply looked for the anchor tag's text and based on that filled a local var with the ID that would be targeted for the indicator. It then passed that ID to the <em>fillBox()</em> method.

<h2>A Little Roadblock</h2>

I thought I was done and the code look pretty straightforward. When I ran this, though, I experienced some odd behavior:

<a href="http://blog.reybango.com/wp-content/uploads/2010/07/throbber.png"><img src="http://blog.reybango.com/wp-content/uploads/2010/07/throbber.png" alt="" title="throbber" width="619" height="414" class="alignright size-full wp-image-959" /></a>

When I would click on the "Box 1" link, the indicator would correctly appear in the first DIV followed by the data populating the box. When I would next click on the "Box 3" link, though, both the first box <strong>AND</strong> the third box would have the indicators displayed! Not good. 

I looked into it and got feedback from Adam Sontag who provided the answer I needed. I had incorrectly assumed that <em>ajaxStop()</em> would unbind the jQuery global Ajax events from the attached element. Unfortunately it doesn't so by using the <em>unbind()</em> method, I was able to resolve the issue.

[code lang="js"]			
		$.ajax({
		  url: 'test.php',
		  cache: false,
		  success: function(data) {
			
			$(ele).html( data ).unbind( 'ajaxStart' ).unbind( 'ajaxStop' );

		  }
		});

	};
[/code]


