36

I'm using $.ajax() to populate a list in my mobile web app. What I'd like to do is have the jQuery mobile loading spinner appears while this call is being performed and disappear once the list populates. The current version of JQM uses $.mobile.showPageLoadingMsg() and $.mobile.hidePageLoadingMsg() to show and hide the loading spinner, respectively. I can't figure out where exactly to place these statements to get the correct result. This seems like it should be a fairly easy thing to accomplish, I just haven't been able to find anything about this exact scenario.

Here's the ajax call inside the pagecreate function:

$('#main').live('pagecreate', function(event) {
        $.ajax({
            url: //url
            dataType: 'json',
            headers: //headers
            success: function(data) {
                for(i = 0; i < data.length; i++) {
                    $('#courses').append('<li>' + data[i].name + '<ul id="course' + data[i].id + '"></ul>' + '<span class="ui-li-count">' + data[i].evaluatedUserIds.length + '</span></li>');
                    $('#course' + data[i].id).listview();
                    for(j = 0; j < data[i].evaluatedUserIds.length; j++) {
                        $('#course' + data[i].id).append('<li><a href="">' + data[i].evaluatedUserIds[j] + '</a></li>');
                    }
                    $('#course' + data[i].id).listview('refresh');
                }
                $('#courses').listview('refresh');
            }
        });
    });
Sean
  • 5,810
  • 2
  • 33
  • 41

8 Answers8

58

You can use the beforeSend and complete events of $.ajax to call $.mobile.showPageLoadingMsg and $.mobile.hidePageLoadingMsg. Would look like this:

$('#main').live('pagecreate', function(event) {
        $.ajax({
            beforeSend: function() { $.mobile.showPageLoadingMsg(); }, //Show spinner
            complete: function() { $.mobile.hidePageLoadingMsg() }, //Hide spinner
            url: //url
            dataType: 'json',
            headers: //headers
            success: function(data) {
                //...
            }
        });
    });
Alex Turpin
  • 46,743
  • 23
  • 113
  • 145
  • I also tried this at first, but it doesn't seem to work either. The ajax call is happening inside the pagecreate function. Could that have something to do with it? – Sean Aug 26 '11 at 17:53
  • tried that too. no such luck. i'm not sure what's going on, bug perhaps? ultimately, it's not that big of a deal for the moment. – Sean Aug 26 '11 at 18:27
  • Try replacing the `$.mobile.showPageLoadingMsg();` by an alert. – Alex Turpin Aug 26 '11 at 18:47
  • Either `$.mobile.showPageLoadingMsg()` isn't working or your JSON request is so fast you don't see the spinner appearing. – Alex Turpin Aug 26 '11 at 19:17
  • Its working. And i guess its the correct way of doing it. thanks Xeon06. – ASD Jun 05 '12 at 10:06
  • @Xeon06 just add a semicolon after $.mobile.hidePageLoadingMsg() – Varun Nath Sep 19 '13 at 11:06
  • Worked for me instantly. Thanks for saving time and posting precise, compact and working code. – zeeshan Apr 26 '14 at 13:53
50

Before JQM 1.2:

$(document).ajaxStart(function() {
    $.mobile.showPageLoadingMsg();
});

$(document).ajaxStop(function() {
    $.mobile.hidePageLoadingMsg();
});

Since JQM 1.2:

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

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

http://api.jquerymobile.com/page-loading/

Jason
  • 2,223
  • 2
  • 20
  • 28
Marvin Emil Brach
  • 3,984
  • 1
  • 32
  • 62
  • I am using jQueryMobile 1.1 and implemented $.mobile.showPageLoadingMsg(); and then $.mobile.hidePageLoadingMsg(); but it only worked on firefox... it doesnt do anything on chrome or my safari.. any ideas why? – Dan Dec 21 '12 at 06:30
  • Is there an output in console? – Marvin Emil Brach Jan 07 '13 at 08:34
  • This is a fantastic solution! Prevents coding (or potentially forgetting) to show the spinner on every AJAX call. – SharpC Oct 27 '18 at 17:07
14

A few people have asked about the workaround I ended up implementing, so I figured I'd share it. It's nothing particularly elegant or complicated, but it did seem to work. I haven't used the framework since the official 1.0 was released, so this may have been solved in the update. Essentially, I put the $.mobile.showPageLoadingMsg() call into the pageshow function, but wrapped it in an if clause that only fires the first time the page is shown:

var mainloaded = false;

$('#main').live('pageshow', function(event) {   //Workaround to show page loading on initial page load
    if(!mainloaded) {
    $.mobile.showPageLoadingMsg();
    }
});

$('#main').live('pagecreate', function(event) { 
    $.ajax({
        url: //url
        dataType: //datatype,
        headers: //headers
        success: function(data) {
            //
            //...loading stuff
            //
            $.mobile.hidePageLoadingMsg();
            mainloaded = true;
        }
        //
        //...handle error, etc.
        //
    });
});
Sean
  • 5,810
  • 2
  • 33
  • 41
  • you are correct about moving the show from the pagecreate event, since right after this event JQM calls hidePageLoadingMsg since the page loading has finished (and this overrides your call) – talkol Mar 18 '12 at 18:38
10

This is a bit late...but you need to:

  1. Call $.mobile.showPageLoadingMsg() before the AJAX call.
  2. Make the AJAX call. The call needs to be sent asynchronously (put async: true in your call).
  3. Add $.mobile.hidePageLoadingMsg() in your success() function.
Jason Plank
  • 2,336
  • 5
  • 31
  • 40
Ben
  • 1,434
  • 14
  • 23
  • Yeah, that's basically what other people said, and also the first thing I tried. The conclusion I came to was that there was a bug in the version of the beta I was using that was causing the loading message to not be displayed upon initial page load. I ended up finding a workaround. Thanks anyway, for the response. – Sean Oct 12 '11 at 11:22
  • @Sean, I seem to have the same problem you described. Could you please provide me the workaround you've found? Thank you – Raphael Müller Dec 07 '11 at 09:56
  • what happens if you need the call to be async = false? – Dan Dec 24 '12 at 01:27
  • was searching for this answer for hours! – user3023313 Jan 20 '14 at 20:24
9
$(document).ajaxSend(function() {
    $.mobile.loading( 'show');
});
$(document).ajaxComplete(function() {
    $.mobile.loading( 'hide');
});
Patrioticcow
  • 26,422
  • 75
  • 217
  • 337
3

Or, the simplest way is to put it globally as a separation of concern -

Put below code into your master/layout view

   <script type="text/javascript">

    $(document).bind('mobileinit', function () {
        //Loader settings
        $.mobile.loader.prototype.options.text = "Loading..";
        $.mobile.loader.prototype.options.textVisible = true;
        $.mobile.loader.prototype.options.theme = "b";
        $.mobile.loader.prototype.options.textonly = false; 
    }); 

    $(document).on({
        ajaxSend: function () { $.mobile.showPageLoadingMsg(); },
        ajaxStart: function () { $.mobile.showPageLoadingMsg(); },
        ajaxStop: function () { $.mobile.hidePageLoadingMsg(); },
        ajaxError: function () { $.mobile.hidePageLoadingMsg(); }
    });

</script> 

Edit: Please use instead if you are targeting latest version of JQM (>1.2):

  • $.mobile.loading('show');
  • $.mobile.loading('hide');
sandeep talabathula
  • 3,238
  • 3
  • 29
  • 38
3

You should do $.mobile.showPageLoadingMsg() just before the ajax call, and $.mobile.hidePageLoadingMsg() in the success (or fail) block so it goes away once a result comes back.

I've never used jQuery mobile, but it should operate the same as showing/hiding a regular ol' spinning image.

degenerate
  • 1,224
  • 1
  • 14
  • 35
  • 1
    Yeah, that was the first thing I tried, but it doesn't seem to do anything. I've tried leaving out the hide call to see if the show call was working at all (instead of going away too quickly to see), but no such luck. – Sean Aug 26 '11 at 17:50
2

The problem here is that the call to $.ajax() happens within the control flow of the event handler (the caller).

A very simple way to decouple the ajax request from this control flow is to let setTimeout() invoke this function for you, like so:

setTimeout(function(){$.ajax( ... )}, 1);

You can then use the 'beforeSend' and 'complete' events of $.ajax() as stated before and be sure, that your spinner is showing up.

juleq
  • 31
  • 2