7

I am trying to display a loading spinner for during ajax calls on my page. I want to target different ajax calls and display different spinners. As things stands, as ajaxStart is a global event, an all ajax calls end up displaying all spinners at the same time.

This works...it adds the class "loading" to a hidden div containing the spinner and displays it.

$(document).bind("ajaxStart", function () {
    $body.addClass("loading");
});

$(document).bind("ajaxStop", function () {
    $body.removeClass("loading");
});

Now from other stack answers I have seen that you can add namespaces to ajaxstart/stop (jQuery should I use multiple ajaxStart/ajaxStop handling)

......along the lines of

$(document).bind("ajaxStart.secondCall", function () {
    $body.addClass("loading2");
});

$(document).bind("ajaxStop.secondCall", function () {
    $body.removeClass("loading2");
});

But this doesn't work in its current form. Any guidance would be appreciated...

UPDATE:

AS AN ADDITION TO ILYAS SOLUTION AND BASED ON HIS GUIDANCE I IMPLEMENTED THE AJAX START FUNCITONALITY IN MY AJAX CALL ....

function sendResponse(thread_id){
        $(document).off(".reference_call");
         $(document).on("ajaxStart.secondCall", function () {
         $('.spinner').show();
      });
 $.ajax({
    url: 'someURL.php',
    type: 'post',
    data: {
              //data
         },
            success: function(data) {
            $(document).on("ajaxStop.secondCall", function () {
               $('.spinner').hide();
            });
                    //do stuff....

                    } else {

                     //do stuff....
                    }
              }
        });
  return false;
}
Community
  • 1
  • 1
GhostRider
  • 2,109
  • 7
  • 35
  • 53
  • 1
    Are you sure your callbacks not firing? Here is simple [jsfiddle](http://jsfiddle.net/9yywwsjt/1/) works as expected. – Ilya Luzyanin Aug 27 '14 at 15:19
  • Iilya, thanks for your comment. The problem is that I want the first set of functions to attach the loading class to the body and the second function to occur for a separate ajax call at a separate time. At the moment both are called for any ajax call on that page - I do understand why this is happening but I don't know how to target different ajax calls on the same page separately – GhostRider Aug 27 '14 at 19:21
  • Oh, I see what you mean now. So, I have 2 questions: can you move the logic on what spinner to display inside your ajaxStart and ajaxStop callbacks? If not - have you tried binding to ajax events before sending the request and then unbinding after request is complete? – Ilya Luzyanin Aug 27 '14 at 19:31
  • Ilya, about binding - this is what I considered but I could not get it to work - this is because I am pretty new to jquery and I am sure NOT because it doesn't work. Although it sounds like spoon feeding - if you could point me in the right direction with an example of how you'd implement this if be most grateful... – GhostRider Aug 27 '14 at 20:07
  • Also - getting the spinner logic inside the ajax call is not something I had thought of but intuitively I wonder if 'binding' is the way to go. I did also try to set a random variable to 'true' within one of the ajax calls, and then in the ajax start function add a conditional 'if x is true' then.....spinner. But that didn't work either. Arghhh there must be a solution to the 'global' problem with ajax start.... – GhostRider Aug 27 '14 at 20:08
  • 1
    Here, I've updated my [jsfiddle](http://jsfiddle.net/9yywwsjt/3/), if that's something like what you wanted, I will make it an answer. – Ilya Luzyanin Aug 27 '14 at 20:27
  • Simply superb. Make it an answer and give me some time to then tick it. My hat is off to you....! – GhostRider Aug 27 '14 at 21:06

3 Answers3

11

So, as it was mentioned in the discussion linked to the question, you can bind to and unbind from ajax events using your custom namespaces. Here is simple example demonstrating this approach. In the first part of your code you bind to ajax events with .firstCall namespace, like this:

$(document).on("ajaxStart.firstCall", function () {
    $('.spinner1').show();
});
$(document).on("ajaxStop.firstCall", function () {
    $('.spinner1').hide();
});
// then goes your ajax call

Later in code, when you need to send second ajax with different spinner, you must unbind from .firstCall namespace and bind to .secondCall like this:

$(document).off(".firstCall");
$(document).on("ajaxStart.secondCall", function () {
    $('.spinner2').show();
});
$(document).on("ajaxStop.secondCall", function () {
    $('.spinner2').hide();
});
// then goes your second ajax call

As an alternative you might consider using one set of global ajax events handlers, and move your logic on what spinner to show/hide inside those callbacks, but this really depends on what logic that is.

Ilya Luzyanin
  • 7,910
  • 4
  • 29
  • 49
0

I've found this implementation more reliable (especially when you are using promises and multiple async calls):

$(document).ajaxStart(function(r) {
  if ($('#d-loading').is(':hidden')) {
    $('#d-loading').modal('show');
    }

}).ajaxStop(function(r) {
  if ($('#d-loading').is(':visible')) {
    $('#d-loading').modal('hide');
  }

}).ajaxError(function(event, request, settings) {
  //Deal with error here
});

I'm using a Bootstrap Modal, which I activate or deactivate. Hope it helps!

Théo T. Carranza
  • 7,813
  • 1
  • 21
  • 14
0

I had same issue and resolve with $.active and beforeSend : function(){},

Issue : I have some code in set interval for refreshing notification and we applied loding overlay globally so all AJAX load that overlay and every set interval showing interval.SO How to remove that overlay for particular ajax ?

  1. setInterval(function () { RefreshNotification(); }, 10000);
                    $(document).ajaxStart(function () {        
                        $('#dvLoading').show();
                    });
                    $(document).ajaxStop(function () {
                        $('#dvLoading').hide();
                    });

Solution : How to remove over lay **Solution 1 : **
Simple hide overlay on beforesend

$.ajax({
        type: 'GET',
        datatype: 'HTML',
        url: NotificationURL,
        beforeSend: function () {

                $('#dvLoading').hide();

        },
        success: function (result) { }

});

Problem : If parallel request then above code not work

Solution 2 : Simple hide overlay on beforesend and check condition for total ajax request

$.ajax({
        type: 'GET',
        datatype: 'HTML',
        url: NotificationURL,
        beforeSend: function () {
            //console.log($.active);
            if ($.active < 2) {
                $('#dvLoading').hide();
            }
        },
        success: function (result) {
            $("#header_notification_bar").html("");
            $("#header_notification_bar").html(result);
        },
        error: function
            (XMLHttpRequest, textStatus, errorThrown) {
           alert(errorThrown);
        }
    });

Enjoy above code should work perfectly

MSTdev
  • 4,507
  • 2
  • 23
  • 40