Weblurk
Weblurk

Reputation: 6802

Ajax complete is fired before success is ready, how can one prevent this behaviour?

I have an AJAX request which fetches a chunk of HTML which I insert into the DOM. While this is happening I am showing a spinner loading gif.

I want the spinner to hide at the exact same time as the data received from the ajax request is inserted into the DOM.

The problem is that the javascript starts executing the complete part before the HTML is actually inserted into the DOM. So for the end user the spinner goes away and a while after, the DOM pops up.

 $('#mySpinner').show();
 $.ajax({
     success: function(data) {
         $('#myElement').html(data);
     },
     complete:(){
         $('#mySpinner').hide(); // This is called when the success part is still executing
     }
 });

EDIT: I'm not saying complete is fired before success. I am saying complete is fired before success is ready. So the order in what happens is this:

  1. Success is called
  2. $('#myElement').html(data); is called
  3. Complete is called
  4. $('#mySpinner').hide() is called
  5. $('#mySpinner').hide() is finished
  6. $('#myElement').html(data); is finished

Upvotes: 0

Views: 1064

Answers (3)

mhu
mhu

Reputation: 18041

html() runs synchronously, however the browser could still be rendering when the next statement is executed. You could try to add a simple setTimeout to give the browser time to display the added content:

$('#mySpinner').show();
$.ajax({
    success: function(data) {
        $('#myElement').html(data);
        setTimeout(function() {
            $('#mySpinner').hide();
        }, 0);
    },
    error: function() {
        $('#mySpinner').hide();
    } 
});

Another option is to add a specific element to the added html and only continue when that element exists:

function waitForDom(el, cb) {
    if ($(el).length) {
        $(el).remove();
        cb();
        return;
    }

    setTimeout(function() {
        waitForDom(el, cb);
    }, 10);
}

$('#mySpinner').show();
$.ajax({
    success: function(data) {
        $('#myElement').html(data + '<div id="waitForDom"></div>');

        waitForDom("waitForDom", function() {
            $('#mySpinner').hide();
        });
    },
    error: function() {
        $('#mySpinner').hide();
    } 
});

Upvotes: 1

emrea
emrea

Reputation: 137

You can simply hide your spinner in success part of ajax code:

$('#mySpinner').show();
 $.ajax({
     success: function(data) {
         $('#myElement').html(data);
         $('#mySpinner').hide();
     }
 });

Upvotes: 0

Laurent S.
Laurent S.

Reputation: 6946

Just do this then :

$('#mySpinner').show();
$.ajax({
    success: function(data) {
     $('#myElement').html(data);
     $('#mySpinner').hide();
 }

});

But the behaviour you describe is not inline with jQuery doc as complete should only occur after success and error ... can you reproduce this wrong behaviour in a jsFiddle ? It might be the problem is somewhere else...

Upvotes: 4

Related Questions