82

How do I display a spinning "busy" indicator at a specific point in a web page?

I want to start/stop the indicator when an Ajax request commences/completes.

Is it really just a matter of showing/hiding an animated gif, or is there a more elegant solution?

Tony the Pony
  • 40,327
  • 71
  • 187
  • 281

9 Answers9

97

You can just show / hide a gif, but you can also embed that to ajaxSetup, so it's called on every ajax request.

$.ajaxSetup({
    beforeSend:function(){
        // show gif here, eg:
        $("#loading").show();
    },
    complete:function(){
        // hide gif here, eg:
        $("#loading").hide();
    }
});

One note is that if you want to do an specific ajax request without having the loading spinner, you can do it like this:

$.ajax({
   global: false,
   // stuff
});

That way the previous $.ajaxSetup we did will not affect the request with global: false.

More details available at: http://api.jquery.com/jQuery.ajaxSetup

leech
  • 8,293
  • 7
  • 62
  • 78
Rod
  • 2,046
  • 2
  • 20
  • 24
  • 2
    +1 for `ajaxSetup()`. Would prefer if further explanation about the `global` property was given. – RabidFire Dec 04 '10 at 19:12
  • @RabidFire, actually global is not needed here, it's just for $.ajax – Rod Dec 04 '10 at 19:34
  • @gov, positioning the gif depends of the layout, you can just hide / show the div where it's placed, instead of modifying dom. – Rod Dec 04 '10 at 19:40
  • 1
    This looked promising but it didn't work for me, ended up trying a different solution that worked. http://stackoverflow.com/questions/7003707/getting-jquery-beforesend-and-complete-to-work-in-rails-3 – Bob Aug 10 '11 at 03:48
  • If you have 2 XHRs, and the first one finishes right after the second one starts, this code hides the loading indicator even though the second XHR is still running. – Mark E. Haase Feb 25 '16 at 04:10
  • Warning! This answer is outdated. As noted in the [jQuery.ajaxSetup API](http://api.jquery.com/jQuery.ajaxSetup/) you should now use the global Ajax event handler methods: `.ajaxStart()`, `.ajaxStop()`, etc... – Mariano Desanze Feb 27 '16 at 16:22
  • amazing and awesome solutions. – 3 rules Aug 27 '16 at 12:14
41

The jQuery documentation recommends doing something like the following:

$( document ).ajaxStart(function() {
  $( "#loading" ).show();
}).ajaxStop(function() {
  $( "#loading" ).hide();
});

Where #loading is the element with your busy indicator in it.

References:

Mariano Desanze
  • 7,847
  • 7
  • 46
  • 67
Sean W.
  • 4,580
  • 4
  • 22
  • 22
  • 1
    These seem more useful than beforeSend and complete, because ajaxStart will "...Register a handler to be called when the first Ajax request begins" and ajaxStop will "...Register a handler to be called when all Ajax requests have completed" - these handle concurrent async messages and wont hide the "please wait" indicator prematurely. – gap May 27 '15 at 14:34
10

I tend to just show/hide a IMG as other have stated. I found a good website which generates "loading gifs"

Link I just put it inside a div and hide by default display: none; (css) then when you call the function show the image, once its complete hide it again.

Elliott
  • 3,812
  • 24
  • 69
  • 93
6

yes, it's really just a matter of showing/hiding an animated gif.

Chase Florell
  • 46,378
  • 57
  • 186
  • 376
  • 2
    Agreed. Show/hide an image is easy and understood by all browsers. There are a couple jquery rotate plugins for images but those won't work in all browsers. – Mike Blandford Dec 04 '10 at 19:29
  • @mike my solution is working fine for my project in all browsers, do you think that is nice approach – kobe Dec 04 '10 at 19:30
5

I did it in my project ,

make a div with back ground url as gif , which is nothing but animation gif

<div class="busyindicatorClass"> </div>

.busyindicatorClass
{
background-url///give animation here
}

in your ajax call , add this class to the div and in ajax success remove the class.

it will do the trick thatsit.

let me know if you need antthing else , i can give you more details

in the ajax success remove the class

success: function(data) {
    remove class using jquery
  }
kobe
  • 15,671
  • 15
  • 64
  • 91
4

To extend Rodrigo's solution a little - for requests that are executed frequently, you may only want to display the loading image if the request takes more than a minimum time interval, otherwise the image will be continually popping up and quickly disappearing

var loading = false;

$.ajaxSetup({
    beforeSend: function () {
        // Display loading icon if AJAX call takes >1 second
        loading = true;
        setTimeout(function () {
            if (loading) {
                // show loading image
            }
        }, 1000);            
    },
    complete: function () {
        loading = false;
        // hide loading image
    }
});
John M
  • 2,510
  • 6
  • 23
  • 31
3

I did it in my project:

Global Events in application.js:

$(document).bind("ajaxSend", function(){
   $("#loading").show();
 }).bind("ajaxComplete", function(){
   $("#loading").hide();
 });

"loading" is the element to show and hide!

References: http://api.jquery.com/Ajax_Events/

albert yu
  • 165
  • 1
  • 5
3

I had to use

HTML:
   <img id="loading" src="~/Images/spinner.gif" alt="Updating ..." style="display: none;" />

In script file:
  // invoked when sending ajax request
  $(document).ajaxSend(function () {
      $("#loading").show();
  });

  // invoked when sending ajax completed
  $(document).ajaxComplete(function () {
      $("#loading").hide();
  });
Ken Mc
  • 1,268
  • 15
  • 12
2

Old thread, but i wanted to update since i worked on this problem today, i didnt have jquery in my project so i did it the plain old javascript way, i also needed to block the content on the screen so in my xhtml

    <img id="loading" src="#{request.contextPath}/images/spinner.gif" style="display: none;"/>

in my javascript

    document.getElementsByClassName('myclass').style.opacity = '0.7'
    document.getElementById('loading').style.display = "block";