1

I'm building a web app with a lot of ajax calls, 100+ which I'm using to inject all my content in my web app.

I was hoping to find a way to hide the page and show the ajax spinner until all the ajax calls are complete... and/or the whole app is loaded, then display the site.

otherwise the user can navigate pages that A. might not be fully rendered correctly or B. will be mid navigation when the site refreshes to Home when fully loaded.

I came across the guts of a solution but not sure how to implement. or put the two together... college project so far from a pro but these looked promising...

https://stackoverflow.com/a/14038050

 $(document).ajaxStop(function () {
      // $.active == 0 
  });

https://stackoverflow.com/a/12313138/2676129

$(document).ajaxStart(function() {
    $.mobile.loading('show');
});

$(document).ajaxStop(function() {
    $.mobile.loading('hide');
});

How might I get this to work? my ajax calls are referenced across a number of .js files (different sections of app)

thanks very much for any help!

edit : example ajax call used

$.ajax(
        {
            url: "http://myurl",
            type: 'get',
            dataType: 'jsonp',
            success: function(data)
            {
                if (data.result == 'success')
                {
                    var previousPageID = "";
                    var currentPageID = "";
                    $.each(data.data, function(key, data)                 //scans through each Lv1 Category, creates a button and page and links thems.
                    {
                        var divLabel = data.label;
                        var pageID = currentPageID + data.label.replace(/\s/g, "");
                        $('#contentPage').append(generateButtons(pageID, divLabel));                                                       //generates a normal button for a category from CMS and generates the relevant page to link to.
                        var previousPageID = currentPageID;
                        generateNextPage(data, previousPageID);
                    });
                    $("#Page").trigger("create");                                              //once html is injected into home <div> applies jquery mobile styling and effects (enhance)
                }
            }
        });
Community
  • 1
  • 1
alhimself
  • 21
  • 1
  • 1
  • 5

2 Answers2

12

Just wanted to point out a simpler solution but yet effective. You will need to append this loading div to your page.

<div id="loading"></div>

After that with the following we make sure that this div is going to be shown or hidden whenever an ajax call starts and stops respectively.

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

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

Lastly, add the following CSS to ensure that the the div will display full screen like a blocked UI element (which suggests that the page is loading something/ instead of the spinner).

#loading {
    width: 100%;
    height: 100%;
    position: fixed;
    top: 0;
    left: 0;
    background-color: rgba(0,0,0,.5);
    -webkit-transition: all .5s ease;
    z-index: 1000;
    display:none;
}

Demo JSFIDDLE here

nmargaritis
  • 859
  • 7
  • 21
  • If the ajax is not triggered via jQuery, will this method work? – Frozen Flame May 12 '15 at 02:07
  • @FrozenFlame if you do not want to use jQuery at all you need to replace the part that determines when a ajax call start or ends. How do you make ajax calls (xmlhttprequests)? – nmargaritis May 12 '15 at 05:57
2

One approach would be to display your loading animation as part of your initial page & page load.

Then, wait for your outstanding ajax calls to reach zero and once that happens, hide the loading animation.

Your document ready would look something like:

$(document).ready(function() {
    $('#spinner').addClass('spin');

    function stopSpinner() {
        $('#loading').addClass('hide');
        $('#loading').one('webkitTransitionEnd', function() {
            $('#loading').hide();
        });
    }

    $(document).ajaxStop(function () {
        // $.active == 0 
        stopSpinner();
    });
});

Your markup would have something like this as the last elements in the body:

<div id="loading">
    <div id="spinner"></div>
</div>

With styles like this:

#loading {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background-color: rgba(0,0,0,.5);
    -webkit-transition: all .5s ease;
    z-index: 1000;
}

#loading.hide {
    opacity: 0;
}

#spinner {
    position: absolute;
    width: 100px;
    height: 100px;
    top: 50%;
    left: 50%;
    margin-top: -50px;
    margin-left: -50px;
    background-color: yellow;
    -webkit-transition: all 1000s linear;
}

#spinner.spin {
    -webkit-transform: rotate(100000deg);
}

The really long transition time and large rotation are there to simulate a forever animation. You could also replace this with an a CSS3 animation, animated GIF or other to get the effect you want.

Demo fiddle (note: it just uses setTimeout to fake the callback to hide the loader)

dc5
  • 12,341
  • 2
  • 35
  • 47
  • hi thanks for getting back to me and taking the time. drop it in as is to test, the "spinner" shows as per the fiddle but unfortunately never hides after all ajax complete – alhimself Aug 28 '13 at 23:49
  • I haven't use $.ajaxStop myself, but from the docs it should work. There is an additional note though: "If $.ajax() or $.ajaxSetup() is called with the global option set to false, the .ajaxStop() method will not fire." I don't know if this applies to your code or not. – dc5 Aug 28 '13 at 23:53
  • Here's an [updated fiddle](http://jsfiddle.net/Luj5m/3/) with it working with an outstanding ajax call. It loads jsfiddle.net into a result div. The alerts show the number of outstanding requests. – dc5 Aug 29 '13 at 00:02
  • edit: included example ajax call. @dc5 i'll look into it further, thanks for the efforts, it obviously should work...i pray my ajax calls actually do end... my console says yay, .ajaxstop() he say nay apparently. – alhimself Aug 29 '13 at 00:20
  • hi @dc5 thanks for the input after a bit more googling i managed to get a spinner working, not using ajaxstart/stop but the settimer you used to illustrate the function in your fiddle. once i tailored the timing worked as needed! thanks for indirect help! – alhimself Sep 10 '13 at 14:25
  • @alhimself I'm glad you found a solution that works for you. Using a timer can be a bit brittle as response times can vary with congestion and load - just something to watch out for. If you have a solution that is different from the above that works for you, I'd encourage you to post it as an answer and mark it as such so this question doesn't remain open. – dc5 Sep 10 '13 at 15:51
  • i am aware of this issue and will have to tailor timers on final build, not perfect i know unfortunately, so its a "fix" not a solution. but for now its all i have as i cant get ajaxstop() to work. will leave question open if any one else can help. my $.ajax() calls have no global option set to false, unless its false by default...? thanks again! – alhimself Sep 10 '13 at 20:23
  • [link]http://lynnrockets.files.wordpress.com/2010/08/political-pictures-sarah-palin-whoosh.jpg I would love to know how to do that..... but unfortunately its way beyond me but again thanks very much for the input without stack overflow id be in deep water on this app learned so much! I cant upvote your answer by the way not enough rep :( but ill give ++1 from here – alhimself Sep 11 '13 at 03:41
  • @alhimself In chrome, you can see all XHR requests in the network tab in the developer tools. The initiator column should show you the line number that made the call. It's not a full stack trace, but maybe that will help you narrow down what might be making the request outside of jQuery. – dc5 Sep 11 '13 at 04:20