Set a wait image with JQuery for asyncronous operations

I’m modifying an ASP.NEt site to achieve better performances, I’m actually moving some operations client-side with jquery. A typical pattern is to issue requests to a webservice instead of making a postback of the whole page. Here is a typical situation, I have a lot of rows in a grid and the user must be able to change some values.

image

A standard asp.net approach uses an autopostback dropDownList to do a postback when the user change a value, but this force the server to render the whole page again. This is a tremendous waste of resource, because the page has a big viewstate. The obvious solution is to use JQuery or some other client side script library to invoke a webservice function. I use a simple JQuery script that hides all the dropDownList and insert a click handler on the value, in this way when the user click on a value the dropdownlist appears.

image

The layout is much more clearer, beacuse all the dropdownlists disappeared, and they are shown only when the user want to change a value. When the user changes value I simply call a webservice function that does all the stuff, and update the interface accordingly. Since the response type from the webservice cannot be estimated (this operation sometime can trigger a massive update of thousands of records  ) I need to inform the user that the operation is in progress. This is a very common pattern, so I decided to create a little JQuery extension to manage this. Here is how I use it

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
$('select[id$=ddlMassiveAvgDomainContext]')
  .hide()
  .change(function() {
      $(this).parent().setwait({waitoffset: 1000});
      //Qui à ¨ dove debbo aggiornare il servizio
      Rilevazioni.MassiveUpdateTargetContext(
      $(this).attr('relid'),
      $(this).val(),
       function(result, context, method) {
          $(context).parent().clearwait();
          var labelRelated = $(context).toggle()[0].data;
          $(labelRelated).text(result);
       },
      function(error, context, method) {
         $(context).parent().clearwait();
         alert('Si sono verificati errori.');
         $(context).toggle();
      },
      this);

Th code is really simple, I select all the dropdownlist of interest, then hide them all, then wire the change event. Inside the event I grab the div that contains the cell with $(this).parent() and use my setwait extension, specify an offset of one second, this means that if the server answer before one second nothing is shown, if more than one second elapses a wait image get shown. When the webserver returns I call clearwait to return the DOM to the original state. Here is what happens

image

I show two div, one with 0.5 opacity and white background, and then another div with a gif image as background. Now the user is informed that the server is working. Here is the code of the extender.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
(function($) {

   $.fn.setwait = function(options) {
      var settings = $.extend({
         slidecss: 'waitindicatormasx',
         imagecss: 'waitindicator',
         waitoffset: 200
      }, options || {});
      var context = this;
//      debugger;
      context[0].timer = setTimeout(function() {
         var position = context.position();
         var thediv = context;
         var innerslide = $('<div style="width:' + thediv.width() + 'px; height:' + thediv.height() + 'px" class="' + settings.slidecss + '" />')
           .css('opacity', 0.5);
         var progress = $('<div style="width:' + thediv.width() + 'px; height:' + thediv.height() + 'px" class="' + settings.imagecss + '"/>');
         thediv.prepend(innerslide)
         thediv.prepend(progress);
         context[0].innerslide = innerslide;
         context[0].progress = progress;
      }, settings.waitoffset);
      return this;
   };
})(jQuery);

(function($) {

   $.fn.clearwait = function() {
      var context = this[0];
      if (context.timer) {
         clearTimeout(context.timer);
      }
      if (context.innerslide) {
         $(context.innerslide).remove();
         $(context.progress).remove();
      }
      return this;
   };
})(jQuery);

And these are the two basic css.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
.waitindicatormasx 
{
   position: absolute;
   background-color: White;
   z-index: 2;
}

.waitindicator 
{
   position: absolute;
   background-image: url(Images/autocomplete.gif);
   background-repeat: no-repeat;
   background-position:center;
   z-index: 3;
}

I have not fully tested it, but it worked well in three different places of the software so I’m quite happy of it. This code simply fires a timer, if the timer elapsed the extender creates two div and prepend them to the target div. The clearwait simply clears the timer (so if the server answer before elapsed time nothing happens), then remove from the dom the two inserted div and everything is back to the original state.

Jquery is really a powerful tool, and a thanks to my friend Andrea Balducci for giving me the original idea of the timer to avoid setting the wait state if the server responds quickly.

alk.

Tags: JQuery Asp.NET