Garbage Burrito!

An internet web blog by Ben Kittrell

Automatic Ajax Loading Images With Prototype

Automatic Ajax Loading Images With Prototype
Ben Kittrell - 08/09/2006 16:32:00
Comments: 21

One of the benefits of using Ajax is that you don't have to refresh the browser to update portions of a page. However the downside of this is if you have network lag for some reason, you could leave the user wondering if you application is working. It's very frustrating to click on a button and have nothing happen. The obvious solution to this is my creating your own "loading..." image.

When I was faced with this problem for doodlekit, my website builder there were two things that bothered me about this solution. Number one, I didn't want to have to call a JavaScript method that the beginning and end of every Ajax call. Number two, I didn't want the loading box to flicker on and off if the request to less than a second or so. Thankfully these issues were fairly easy to solve with Prototype.

First I created the image.

 



Pretty simple. If you're looking for something a little fancier try http://www.ajaxload.info/

Next, a div to hold it.

 

<div id="loading_box" style="display:none"></div>

 

Notice that its hidden by default. Next we need the methods to show and hide this stuff.

 

  var loaded = false;

  function startLoading() {
    loaded = false;
    window.setTimeout('showLoadingImage()', 1000);
  }

  function showLoadingImage() {
    var el = document.getElementById("loading_box");
    if (el && !loaded) {
        el.innerHTML = '<img src="/images/loading.gif">';
        new Effect.Appear('loading_box');
    }
  }

 

The "loaded" variable helps to make sure that the loading box is not display after the Ajax call is complete. startLoading will be used to initiate the loading box. It first sets the loaded flag to false, so we know its still ok to display the loading box. It then sets a timeout on calling the method that actually shows the box. So it wont even try to show the loading box for at least one second.

The showLoadingImage method checks to see if the "loaded" variable has be set to true. If so, we know that the Ajax call is complete and we should not bother displaying the box. To display the box we first add the image tag to the div, and use a Scriptaculous effect to display it.

 

  function stopLoading() {
    Element.hide('loading_box');
    loaded = true;
  }

 

The stopLoading method simply hides the div and sets "loaded" to true. To re-iterate, this is just incase the Ajax call completes before the showLoadingImage method is called.

Now the only thing left is to automatically call these methods at the beginning and end of every Ajax call. Thats where Prototype comes in. Assuming you have the Prototype JavaScript file included, you can simply call the following.

 

  Ajax.Responders.register({
    onCreate : startLoading,
    onComplete : stopLoading
  });

 

After that the loading box will be displayed for any Ajax call lasting longer than one second.

Comments: 21

Comments

1. rheaghen   |   08/11/2006 09:37:46

good practice... but you need a comet connection to show accurate percent completion.

2. thabenksta   |   08/11/2006 10:28:44

I'd never heard of Comet, looks interesting. All the articles I read where like "Comet is the new AJAX". What's up with that phrasing anyway? "Red is the new Black".

I can see were it would be beneficial, but I don't think it will eclipse Ajax because of the long http sessions. This always causes trouble.

"New server software is often required to make applications built using Comet scale, but the patterns for event-driven IO on the server side are becoming better distributed. Even Apache will provide a Comet-ready worker module in the upcoming 2.2 release."

http://www.irishdev.com/NewsArticle.aspx?id=2166

Looks like it could work eventually. But something about it doesn't sit quite right with me.

And quit dropping tech names in my blog anyway ;)

3. Farhad   |   03/16/2007 09:26:13

Thanks

4. Tom  |  my website   |   04/01/2007 13:24:08

When and where should I be calling:

Ajax.Responders.register({
onCreate : startLoading,
onComplete : stopLoading
});

Should I be doing that inside the function where I am calling the ajax request?

5. Ben Kittrell   |   04/03/2007 12:53:53

It can go anywhere. Just put it in a javascript file, and include it. Or just put it in <script tags.

6. Kristoffer   |   06/13/2007 15:40:56

Thank you. Any chance to make it work with a non-Prototype ajax function? This has something to do with Ajax.Responders.register, but I'm not sure what this function does.

7. eliseu   |   07/19/2007 13:56:52

Hi! Nice article. Do you know if Prototype has a way of implementing multiple image loader on a page? The example shown only works for global loading objects (every request made on the page will cause the loading gif show up)

8. marwan   |   08/22/2007 20:25:52

thanx
i try this code but a problem apeare in firefox and IE6.5
at ...
"new Effect.Appear('loading_box');"
the error is
"Effect is not defined"
????

9. Andy   |   09/23/2007 00:46:15

Same error here:

Effect is not defined

10. Anonymous   |   10/04/2007 17:24:17

yjxxxxxxxxxxx

11. cbfdhb  |  my website   |   12/07/2007 10:14:01

wfretew

12. Mike  |  my website   |   12/11/2007 12:17:38

If you see "Effect is not defined". Make sure to install script.aculo.us and it should work.

13. suyash  |  my website   |   12/24/2007 06:04:20

How to show the back end process through code

14. Chris Christopherson  |  my website   |   01/10/2008 12:10:43

You should probably note that this uses Prototype AND Script.aculo.us. It seems that a few didn't catch that.

For those that don't want to load scriptaculous just for this one effect:

element.show(); is part of prototype and will work fine.
http://www.prototypejs.org/api/element/show

$ ( 'loading_box' ).show ( );

Good article, overall!

15. Pedro Miguel   |   05/24/2008 11:16:59

how can i put more than one loading image appearing on different parts of the page? lets say i have two events, that inject ajax responses into two different <divs>. Now i want that a loading image appears on each one of these divs... any ideas??

16. anna kolesnik  |  my website   |   06/18/2008 14:22:38

thanks for your good work ..

17. AhsanbUTT  |  my website   |   06/21/2008 04:12:46

very good article also what i was looking for past few days found that here thx.

18. Sujan   |   06/27/2008 23:09:22

How about using the above with Ajax.Updater? Any Help?

19. Mr Bones   |   10/03/2008 03:56:54

Made a little update on this code.

Ajax.Responders.register({
onCreate : function(){

if(!$('loadingBox')){
loadingB = Builder.node('img',{src:'image.gif', id:'loadingBox', style: ''});
$('id-where-you-will-insert-the-image').appendChild(loadingB);
l = $('loadingBox'); //fix for IE so we can hide
l.hide();
new Effect.Appear('loadingBox');
}
else
{
new Effect.Appear('loadingBox');
}
},
onComplete : function(){
l = $('loadingBox'); //fix for IE so we can hide
new Effect.Fade(l);
}
});

20. fds  |  my website   |   05/08/2009 09:06:05

sdfdsfdsfs

21. ananth@websolusionz.com  |  my website   |   07/25/2011 13:53:33

thanks. the coding is not working for me. i have called the ajax.Responder inside a <script> tag. am i need to use the prototype.js file ?

Post a Comment


Please enter the word below.


powered by Doodlekit™ Free Website Builder by Doodlebit™ Website Company