624

I would like to place a "please wait, loading" spinning circle animation on my site. How should I accomplish this using jQuery?

0

20 Answers 20

1294

You could do this various different ways. It could be a subtle as a small status on the page saying "Loading...", or as loud as an entire element graying out the page while the new data is loading. The approach I'm taking below will show you how to accomplish both methods.

The Setup

Let's start by getting us a nice "loading" animation from http://ajaxload.info I'll be using enter image description here

Let's create an element that we can show/hide anytime we're making an ajax request:

<div class="modal"><!-- Place at bottom of page --></div>

The CSS

Next let's give it some flair:

/* Start by setting display:none to make this hidden.
   Then we position it in relation to the viewport window
   with position:fixed. Width, height, top and left speak
   for themselves. Background we set to 80% white with
   our animation centered, and no-repeating */
.modal {
    display:    none;
    position:   fixed;
    z-index:    1000;
    top:        0;
    left:       0;
    height:     100%;
    width:      100%;
    background: rgba( 255, 255, 255, .8 ) 
                url('https://i.sstatic.net/FhHRx.gif') 
                50% 50% 
                no-repeat;
}

/* When the body has the loading class, we turn
   the scrollbar off with overflow:hidden */
body.loading .modal {
    overflow: hidden;   
}

/* Anytime the body has the loading class, our
   modal element will be visible */
body.loading .modal {
    display: block;
}

And finally, the jQuery

Alright, on to the jQuery. This next part is actually really simple:

$body = $("body");

$(document).on({
    ajaxStart: function() { $body.addClass("loading");    },
     ajaxStop: function() { $body.removeClass("loading"); }    
});

That's it! We're attaching some events to the body element anytime the ajaxStart or ajaxStop events are fired. When an ajax event starts, we add the "loading" class to the body. and when events are done, we remove the "loading" class from the body.

See it in action: http://jsfiddle.net/VpDUG/4952/

20
  • 9
    This is the most in depth solution although I'd recommend you use a centering plugin which centers the preloader around a page element (i.e. body, #element, or .element) Commented Dec 27, 2009 at 1:46
  • 2
    That would be a nice addition, cballou. I was merely trying to keep the information minimized - but as you point out, it certainly can be improved upon.
    – Sampson
    Commented Dec 27, 2009 at 2:02
  • 9
    I had to use .bind() instead of .on() as we are using jQuery 1.5.1! Commented Jul 10, 2012 at 15:09
  • 45
    I'd recommend using the plugin that plugins to the plugins to make sure they're all plugged in. Commented Sep 12, 2012 at 21:25
  • 15
    Note: As of jQuery 1.8, the .ajaxStop() and .ajaxStart() method should only be attached to document. docs
    – balexandre
    Commented Nov 21, 2013 at 8:42
222

As far as the actual loading image, check out this site for a bunch of options.

As far as displaying a DIV with this image when a request begins, you have a few choices:

A) Manually show and hide the image:

$('#form').submit(function() {
    $('#wait').show();
    $.post('/whatever.php', function() {
        $('#wait').hide();
    });
    return false;
});

B) Use ajaxStart and ajaxComplete:

$('#wait').ajaxStart(function() {
    $(this).show();
}).ajaxComplete(function() {
    $(this).hide();
});

Using this the element will show/hide for any request. Could be good or bad, depending on the need.

C) Use individual callbacks for a particular request:

$('#form').submit(function() {
    $.ajax({
        url: '/whatever.php',
        beforeSend: function() { $('#wait').show(); },
        complete: function() { $('#wait').hide(); }
    });
    return false;
});
5
  • 4
    Something to note: if you cant modify the HTML to add the loading img element, you can do it as a background-image on the button using CSS e.g. input.loading-gif{background:url('images/loading.gif');} and then apply the class with jQuery e.g. $('#mybutton').addClass('loading-gif'); The only gotcha is that this will only request the gif when the submit button is clicked, which is normally too late, so you need to pre-cache it, which is easy with jQuery e.g. (new Image()).src = "images/loading.gif";
    – jackocnr
    Commented Feb 23, 2011 at 16:27
  • 4
    This site has a larger and in my opinion nicer selection of loaders with more customization options preloaders.net
    – rorypicko
    Commented Dec 22, 2013 at 19:35
  • FYI: merged from stackoverflow.com/questions/750358/…
    – Shog9
    Commented Jul 25, 2014 at 19:55
  • Nice solution, but when i call show() after hide() it's not working. I found a solution that is switch show() and hide() to toggle(). Hoping it can help someone have same problem as my. Also, I tried solution C) and founded beforeSend not working in async. So, I suggested to call show() above $.ajax to work correctly.
    – 劉鎮瑲
    Commented Aug 16, 2019 at 5:54
  • Thank you very much @Paolo. Personally, I liked your answer than the one accepted by most of the users. Hence, +1 to you from my side. Commented Apr 23, 2020 at 11:59
121

Along with what Jonathan and Samir suggested (both excellent answers btw!), jQuery has some built in events that it'll fire for you when making an ajax request.

There's the ajaxStart event

Show a loading message whenever an AJAX request starts (and none is already active).

...and it's brother, the ajaxStop event

Attach a function to be executed whenever all AJAX requests have ended. This is an Ajax Event.

Together, they make a fine way to show a progress message when any ajax activity is happening anywhere on the page.

HTML:

<div id="loading">
  <p><img src="loading.gif" /> Please Wait</p>
</div>

Script:

$(document).ajaxStart(function(){
    $('#loading').show();
 }).ajaxStop(function(){
    $('#loading').hide();
 });
3
  • This is outdated, as of 1.8.0, .ajaxStart can only be attached to document, ie. $(document).ajaxStart(function(){}).
    – Jonno_FTW
    Commented Apr 14, 2014 at 3:10
  • 2
    @Jonno_FTW fixed. Ta. Old question and answer that's been superceded by Jonathan Sampson's edits to his question, but good to keep it up to date anyway
    – Dan F
    Commented Apr 15, 2014 at 22:06
  • 3
    Jonathan's answer was very in-dept, but this for me was the best for its simplicity. Commented May 13, 2014 at 8:01
20

You can grab an animated GIF of a spinning circle from Ajaxload - stick that somewhere in your website file heirarchy. Then you just need to add an HTML element with the correct code, and remove it when you're done. This is fairly simple:

function showLoadingImage() {
    $('#yourParentElement').append('<div id="loading-image"><img src="path/to/loading.gif" alt="Loading..." /></div>');
}

function hideLoadingImage() {
    $('#loading-image').remove();
}

You then just need to use these methods in your AJAX call:

$.load(
     'http://example.com/myurl',
     { 'random': 'data': 1: 2, 'dwarfs': 7},
     function (responseText, textStatus, XMLHttpRequest) {
         hideLoadingImage();
     }
);

// this will be run immediately after the AJAX call has been made,
// not when it completes.
showLoadingImage();

This has a few caveats: first of all, if you have two or more places the loading image can be shown, you're going to need to kep track of how many calls are running at once somehow, and only hide when they're all done. This can be done using a simple counter, which should work for almost all cases.

Secondly, this will only hide the loading image on a successful AJAX call. To handle the error states, you'll need to look into $.ajax, which is more complex than $.load, $.get and the like, but a lot more flexible too.

4
  • 2
    Thanks for the reply. But tell me, why do I need to use AJAX at all? Can't I simply track down it all in the page itself?
    – thedp
    Commented Dec 27, 2009 at 23:18
  • What exactly do you want to track? Unless you're requesting information after the page has loaded (and AJAX is pretty much the only way to do that without using a plugin), why would you need a "loading" image at all? Commented Dec 28, 2009 at 2:39
  • Samir Talwar: A heavy JavaScript application actually. Thanks, I get the idea.
    – thedp
    Commented Dec 28, 2009 at 6:09
  • Understandable. In that case, just call showLoadingImage before you start and hideLoadingImage after you finish. Should be fairly simple. You may need to stick some sort of setTimeout call in to make sure the browser actually renders the new <img> tag though - I've seen a couple of cases where it doesn't bother until the JavaScript has finished executing. Commented Dec 28, 2009 at 15:38
17

Jonathon's excellent solution breaks in IE8 (the animation does not show at all). To fix this, change the CSS to:

.modal {
display:    none;
position:   fixed;
z-index:    1000;
top:        0;
left:       0;
height:     100%;
width:      100%;
background: rgba( 255, 255, 255, .8 ) 
            url('https://i.sstatic.net/FhHRx.gif') 
            50% 50% 
            no-repeat;
opacity: 0.80;
-ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity = 80);
filter: alpha(opacity = 80)};
1
  • 2
    Edited because the multiple 'background-' lines didn't work, but the single background statement works correctly. Commented Sep 9, 2012 at 14:03
8

SVG animations are probably a better solution to this problem. You won't need to worry about writing CSS and compared to GIFs, you'll get better resolution and alpha transparency. Some very good SVG loading animations that you can use are here: http://samherbert.net/svg-loaders/

You can also use those animations directly through a service I built: https://svgbox.net/iconset/loaders. It allows you to customize the fill and direct usage (hotlinking) is permitted.

To accomplish what you want to do with jQuery, you probably should have a loading info element hidden and use .show() when you want to show the loader. For eg, this code shows the loader after one second:

setTimeout(function() {
  $("#load").show();
}, 1000)
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.0/jquery.min.js"></script>

<div id="load" style="display:none">
    Please wait... 
    <img src="//s.svgbox.net/loaders.svg?fill=maroon&ic=tail-spin" 
         style="width:24px">
</div>

0
7

jQuery provides event hooks for when AJAX requests start and end. You can hook into these to show your loader.

For example, create the following div:

<div id="spinner">
  <img src="images/spinner.gif" alt="Loading" />
</div>

Set it to display: none in your stylesheets. You can style it whatever way you want to. You can generate a nice loading image at Ajaxload.info, if you want to.

Then, you can use something like the following to make it be shown automatically when sending Ajax requests:

$(document).ready(function () {

    $('#spinner').bind("ajaxSend", function() {
        $(this).show();
    }).bind("ajaxComplete", function() {
        $(this).hide();
    });

});

Simply add this Javascript block to the end of your page before closing your body tag or wherever you see fit.

Now, whenever you send Ajax requests, the #spinner div will be shown. When the request is complete, it'll be hidden again.

2
  • Can someone please explain what AJAX has to do with this? Can't I simply manage this all within the page without accessing the server with AJAX... Or am I missing here something? Thanks.
    – thedp
    Commented Dec 27, 2009 at 23:24
  • 4
    Ah - as I understood, you wanted a loading image to be shown whenever you were making AJAX requests. If you simply want a "please wait, loading..." animation to be shown until the page has fully loaded, you could have a loading div in the page and then hide it in your $(document).ready block.
    – Veeti
    Commented Dec 27, 2009 at 23:33
7

If you are using Turbolinks With Rails this is my solution:

This is the CoffeeScript

$(window).on 'page:fetch', ->
  $('body').append("<div class='modal'></div>")
  $('body').addClass("loading")

$(window).on 'page:change', ->
  $('body').removeClass("loading")

This is the SASS CSS based on the first excellent answer from Jonathan Sampson

# loader.css.scss

.modal {
    display:    none;
    position:   fixed;
    z-index:    1000;
    top:        0;
    left:       0;
    height:     100%;
    width:      100%;
    background: rgba( 255, 255, 255, 0.4)
            asset-url('ajax-loader.gif', image)
            50% 50% 
            no-repeat;
}
body.loading {
    overflow: hidden;   
}

body.loading .modal {
    display: block;
}
7

With all due respect to other posts, you have here a very simple solution, using CSS3 and jQuery, without using any further external resources nor files.

$('#submit').click(function(){
  $(this).addClass('button_loader').attr("value","");
  window.setTimeout(function(){
    $('#submit').removeClass('button_loader').attr("value","\u2713");
    $('#submit').prop('disabled', true);
  }, 3000);
});
#submit:focus{
  outline:none;
  outline-offset: none;
}

.button {
    display: inline-block;
    padding: 6px 12px;
    margin: 20px 8px;
    font-size: 14px;
    font-weight: 400;
    line-height: 1.42857143;
    text-align: center;
    white-space: nowrap;
    vertical-align: middle;
    -ms-touch-action: manipulation;
    cursor: pointer;
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    background-image: none;
    border: 2px solid transparent;
    border-radius: 5px;
    color: #000;
    background-color: #b2b2b2;
    border-color: #969696;
}

.button_loader {
  background-color: transparent;
  border: 4px solid #f3f3f3;
  border-radius: 50%;
  border-top: 4px solid #969696;
  border-bottom: 4px solid #969696;
  width: 35px;
  height: 35px;
  -webkit-animation: spin 0.8s linear infinite;
  animation: spin 0.8s linear infinite;
}

@-webkit-keyframes spin {
  0% { -webkit-transform: rotate(0deg); }
  99% { -webkit-transform: rotate(360deg); }
}

@keyframes spin {
  0% { transform: rotate(0deg); }
  99% { transform: rotate(360deg); }
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input id="submit" class="button" type="submit" value="Submit" />

6

Like Mark H said the blockUI is the way.

Ex.:

<script type="text/javascript" src="javascript/jquery/jquery.blockUI.js"></script>
<script>
// unblock when ajax activity stops
$(document).ajaxStop($.unblockUI); 

$("#downloadButton").click(function() {

    $("#dialog").dialog({
        width:"390px",
        modal:true,
        buttons: {
            "OK, AGUARDO O E-MAIL!":  function() {
                $.blockUI({ message: '<img src="img/ajax-loader.gif" />' });
                send();
            }
        }
    });
});

function send() {
    $.ajax({
        url: "download-enviar.do",          
        type: "POST",
        blablabla
    });
}
</script>

Obs.: I got the ajax-loader.gif on http://www.ajaxload.info/

1
5

This would make the buttons disappear, then an animation of "loading" would appear in their place and finally just display a success message.

$(function(){
    $('#submit').click(function(){
        $('#submit').hide();
        $("#form .buttons").append('<img src="assets/img/loading.gif" alt="Loading..." id="loading" />');
        $.post("sendmail.php",
                {emailFrom: nameVal, subject: subjectVal, message: messageVal},
                function(data){
                    jQuery("#form").slideUp("normal", function() {                 
                        $("#form").before('<h1>Success</h1><p>Your email was sent.</p>');
                    });
                }
        );
    });
});
1
5

Most of the solutions I have seen either expects us to design a loading overlay, keep it hidden and then unhide it when required, or, show a gif or image etc.

I wanted to develop a robust plugin, where with a simply jQuery call I can display the loading screen and tear it down when the task is completed.

Below is the code. It depends on Font awesome and jQuery:

/**
 * Raj: Used basic sources from here: http://jsfiddle.net/eys3d/741/
 **/


(function($){
    // Retain count concept: http://stackoverflow.com/a/2420247/260665
    // Callers should make sure that for every invocation of loadingSpinner method there has to be an equivalent invocation of removeLoadingSpinner
    var retainCount = 0;

    // http://stackoverflow.com/a/13992290/260665 difference between $.fn.extend and $.extend
    $.extend({
        loadingSpinner: function() {
            // add the overlay with loading image to the page
            var over = '<div id="custom-loading-overlay">' +
                '<i id="custom-loading" class="fa fa-spinner fa-spin fa-3x fa-fw" style="font-size:48px; color: #470A68;"></i>'+
                '</div>';
            if (0===retainCount) {
                $(over).appendTo('body');
            }
            retainCount++;
        },
        removeLoadingSpinner: function() {
            retainCount--;
            if (retainCount<=0) {
                $('#custom-loading-overlay').remove();
                retainCount = 0;
            }
        }
    });
}(jQuery)); 

Just put the above in a js file and include it throughout the project.

CSS addition:

#custom-loading-overlay {
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    right: 0;
    background: #000;
    opacity: 0.8;
    filter: alpha(opacity=80);
}
#custom-loading {
    width: 50px;
    height: 57px;
    position: absolute;
    top: 50%;
    left: 50%;
    margin: -28px 0 0 -25px;
}

Invocation:

$.loadingSpinner();
$.removeLoadingSpinner();
3

Note that when using ASP.Net MVC, with using (Ajax.BeginForm(..., setting the ajaxStart will not work.

Use the AjaxOptions to overcome this issue:

(Ajax.BeginForm("ActionName", new AjaxOptions { OnBegin = "uiOfProccessingAjaxAction", OnComplete = "uiOfProccessingAjaxActionComplete" }))
1
2

Per https://www.w3schools.com/howto/howto_css_loader.asp, this is a 2-step process with no JS:

1.Add this HTML where you want the spinner: <div class="loader"></div>

2.Add this CSS to make the actual spinner:

.loader {
    border: 16px solid #f3f3f3; /* Light grey */
    border-top: 16px solid #3498db; /* Blue */
    border-radius: 50%;
    width: 120px;
    height: 120px;
    animation: spin 2s linear infinite;
}

@keyframes spin {
    0% { transform: rotate(0deg); }
    100% { transform: rotate(360deg); }
}
1
  • Since the OP is using jQuery they can call $("#loader").toggle(); before making the long running request to start the animation and make another call in the callback function of the request to hide it away. Commented Apr 13, 2018 at 7:51
2

I use CSS3 for animation

/************ CSS3 *************/
.icon-spin {
  font-size: 1.5em;
  display: inline-block;
  animation: spin1 2s infinite linear;
}

@keyframes spin1{
    0%{transform:rotate(0deg)}
    100%{transform:rotate(359deg)}
}

/************** CSS3 cross-platform ******************/

.icon-spin-cross-platform {
  font-size: 1.5em;
  display: inline-block;
  -moz-animation: spin 2s infinite linear;
  -o-animation: spin 2s infinite linear;
  -webkit-animation: spin 2s infinite linear;
  animation: spin2 2s infinite linear;
}

@keyframes spin2{
    0%{transform:rotate(0deg)}
    100%{transform:rotate(359deg)}
}
@-moz-keyframes spin2{
    0%{-moz-transform:rotate(0deg)}
    100%{-moz-transform:rotate(359deg)}
}
@-webkit-keyframes spin2{
    0%{-webkit-transform:rotate(0deg)}
    100%{-webkit-transform:rotate(359deg)}
}
@-o-keyframes spin2{
    0%{-o-transform:rotate(0deg)}
    100%{-o-transform:rotate(359deg)}
}
@-ms-keyframes spin2{
    0%{-ms-transform:rotate(0deg)}
    100%{-ms-transform:rotate(359deg)}
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>


<div class="row">
  <div class="col-md-6">
    Default CSS3
    <span class="glyphicon glyphicon-repeat icon-spin"></span>
  </div>
  <div class="col-md-6">
    Cross-Platform CSS3
    <span class="glyphicon glyphicon-repeat icon-spin-cross-platform"></span>
  </div>
</div>

1

Fontawesome has a loading animation icon which can be used directly in your project without any extra data burden if you are already using font awesome.

<span id="loading" style="display:none"><i class="fa fa-spinner fa-pulse"></i> PLEASE WAIT </span>

Then is jquery you can use following code to show hide the element.

$(document).ajaxSend(function() {
    $('#loading').show();
});

$(document).ajaxComplete(function() {  
    $('#loading').hide();
});

$('button').click(function(){
    $('#loading').toggle();
});
<script src="https://code.jquery.com/jquery-3.6.4.slim.min.js" integrity="sha256-a2yjHM4jnF9f54xUQakjZGaqYs/V1CYvWpoqZzC2/Bw=" crossorigin="anonymous"></script>

<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.1/css/all.css">
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-KK94CHFLLe+nY2dmCWGMq91rCGa5gtU4mk92HdvYe+M/SXH301p5ILy+dN9+nJOZ" crossorigin="anonymous">
<body>
<div class="m-5"> <span id="loading" style="display:none"><i class="fa fa-spinner fa-pulse"></i> PLEASE WAIT </span> </div> 
<button class="btn btn-primary"> Click me to start or stop Ajax </button>
</body>

3
  • This answer could do with a code demonstration of what it looks like when spinning. Commented Mar 1, 2022 at 23:00
  • the only thing this answer brings to the table is using a different asset for the spinner.
    – Kevin B
    Commented Apr 7, 2023 at 20:44
  • if you see other answers where user have to use lots of div, external gif, and many more css, then it is a lot more easier and faster and also light on memory. the code bring performance improvement and less code to the table as well Commented Apr 7, 2023 at 20:49
0

Place this code on your body tag

<div class="loader">
<div class="loader-centered">
    <div class="object square-one"></div>
    <div class="object square-two"></div>
    <div class="object square-three"></div>
</div>
</div>
<div class="container">
<div class="jumbotron">
    <h1 id="loading-text">Loading...</h1>
</div>
</div>

And use this jquery script

<script type="text/javascript">

jQuery(window).load(function() {
//$(".loader-centered").fadeOut();
//in production change 5000 to 400
$(".loader").delay(5000).fadeOut("slow");
$("#loading-text").addClass('text-success').html('page loaded');
});
</script>

See a full example working here.

http://bootdey.com/snippets/view/page-loader

0

I have also found such a problem (challenge) to inform the user about some "info" during the DB response.

My solution is probably a little different than presented here, is it good or bad? I do not know, it was enough for me.

$.ajax({ 
    type: 'ajax',
    method: 'post',
    url: '<?php echo base_url()?>skargi/osluga_skarg',
    data: { full_date: full_date, head_title: head_title },
    //async: false,             
    dataType: 'json',
    beforeSend: function() { $body.addClass("loading"); },
    success: function(data) {   
        $body.removeClass("loading");
0

HTML

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css">
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
<button type="button" id="btn-submit" class="btn btn-info">Submit</button>

  <div class="modal fade" id="loadingModal" tabindex="-1" role="dialog" aria-labelledby="loader" aria-hidden="true" data-keyboard="false" data-backdrop="static">
    <div class="modal-dialog" style="width:50px;padding-top: 15%;">
      <div class="modal-content text-center">
        <img src="https://i.gifer.com/ZZ5H.gif" />    
      </div>
    </div>
  </div>

jQuery

$(function() {
      $('#btn-submit').click(function() {
        $('#loadingModal').modal('show');
      });
    });
-1

It is very simple.

HTML

<link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">

<body>

  <div id="cover"> <span class="glyphicon glyphicon-refresh w3-spin preloader-Icon"></span>Please Wait, Loading…</div>

  <h1>Dom Loaded</h1>
</body>

CSS

#cover {
  position: fixed;
  height: 100%;
  width: 100%;
  top: 0;
  left: 0;
  background: #141526;
  z-index: 9999;
  font-size: 65px;
  text-align: center;
  padding-top: 200px;
  color: #fff;
  font-family:tahoma;
}

JS - JQuery

$(window).on('load', function () {
  $("#cover").fadeOut(1750);
});

Not the answer you're looking for? Browse other questions tagged or ask your own question.