0

I have a page where the user can click a button to retrieve data via an xhr get request. While the data is loading and being parsed, I want a loading message to be displayed, which will be replaced with the data once it is ready. I'm using dojo libraries, so would rather not include jQuery or other libraries.

This is a simplified version of the set up I'm using:

HTML

<div id = "clickMe"> Click Me! </div>
<div id = "results" class = "hidden">
    Please wait while we retrieve the results
</div>

CSS

.hidden {display: none;}

Javascript

// Bind function to click me div
var clickMe = document.getElementById('clickMe');
clickMe.addEventListener('click', getResults, false);

function getResults () {
    // Display the loading message while results are retrieved
    var resultsDiv = document.getElementById('results');
    resultsDiv.classList.remove('hidden');

    // Get the data and parse it here using a standard dojo.xhrGet method
    var displayResults = getData();

    // Output data to resultsDiv, overwriting loading message
    resultsDiv.innerHTML = displayResults;
}

The problem I'm having is that the getResults function always waits until the getData function has completed before removing the 'hidden' class and showing the results div. This means that the user never sees the loading message, only the retrieved data, even if there's a delay while the data is processed. However, if I put an alert in the middle the function is forced to pause, the loading message is displayed:

function getResults () {
    // Display the loading message while results are retrieved
    var resultsDiv = document.getElementById('results');
    resultsDiv.classList.remove('hidden');

    // The loading message will be displayed if this alert is included
    alert ("Hello world!");

    // Get the data and parse it here using a standard dojo.xhrGet method
    var displayResults = getData();

    // Output data to resultsDiv, overwriting loading message
    resultsDiv.innerHTML = displayResults;
}

I have tried replacing the alert with console.log, but it reverts to not showing the loading message. I've also tried setting up getting the data as a callback function inside displaying the loading message, but again it doesn't show anything. I have also tried with the get request set to sync: true as well as sync: false, but again no luck.

How can I make sure the loading message is displayed while waiting for getData?

Edit:

This is the getData function. I have tried both with and without syncing.

function getData() {
    var targetUrl = //some url;
    var restResponse;

    dojo.xhrGet({

        url: targetUrl,
        sync: true; // no difference when this is omitted

        load: function(result) {
            restResponse = result;
        }

    });

    // Parse the rest response - fairly long function so I won't paste it here
    var parsedResponse = parseResult(restResponse);

    return parsedResponse;
}
hopper
  • 13,060
  • 7
  • 49
  • 53
Emma
  • 335
  • 1
  • 4
  • 13
  • 1
    Remove the `=` from the CSS :-) – Bergi Jul 24 '13 at 13:20
  • duplicate of [How to return the response from an AJAX call?](http://stackoverflow.com/questions/14220321/how-to-return-the-response-from-an-ajax-call) – Bergi Jul 24 '13 at 13:21
  • @ Bergi - apologies, I wrote this quickly rather than copy and paste. The = isn't there in my original code :) Have edited accordingly. – Emma Jul 24 '13 at 13:21
  • If you think the duplicate does not apply and need further help, please show us your `getData` function. – Bergi Jul 24 '13 at 13:22
  • Pass `sync: true` in your properties object to [`dojo.xhrGet`](http://dojotoolkit.org/reference-guide/1.9/dojo/xhrGet.html) – Paul S. Jul 24 '13 at 13:23
  • @Bergi - not quite. That question deals with sync vs async; here, I just want the class name 'hidden' to be removed as soon as the script encounters the command rather than waiting until the end of the function. – Emma Jul 24 '13 at 13:24
  • @Emma so you're saying line `var displayResults = getData();` executes before line `resultsDiv.classList.remove('hidden');`? – Paul S. Jul 24 '13 at 13:28
  • Your `getData` function is asynchronous? If yes, you've used it wrong; if it's not then that's your problem. – Bergi Jul 24 '13 at 13:29

2 Answers2

1

My recommendation is to learn how to write asynchronous code and dojo/Deferred.

Instead of getData, rename the method to loadData and

loadData: function() {
    return xhr('', {...}); // this returns a deferred
}

function getResults () {
    var resultsDiv = dom.byId('results');
    domClass.remove(resultsDiv, 'hidden');

    loadData().then(function(displayResults) {
        resultsDiv.innerHTML = displayResults;
    });        
}

http://dojotoolkit.org/reference-guide/1.9/dojo/Deferred.html

Craig Swing
  • 8,152
  • 2
  • 30
  • 43
  • Thanks for this. I've done some more poking around, and discovered that it happens also if I replace the dojo.xhrGet function with a dummy. I'll ask a different question that is phrased better to exclude the dojo part. – Emma Jul 24 '13 at 13:57
0

You can use deffereds and promises in jQuery

http://www.bitstorm.org/weblog/2012-1/Deferred_and_promise_in_jQuery.html. If you work with ajax request you can chain like this (since jQuery 1.8).

var promise1 = $.ajax("/myServerScript1");

function getStuff() {
    return $.ajax("/myServerScript2");
}

promise1.then(getStuff).then(function(myServerScript2Data){
  // Both promises are resolved
});
catalinux
  • 1,462
  • 14
  • 26