I am trying to pull back several sets of statistical data and display progress messages once each set of data has been loaded onto the DOM.
I am trying to use multiple deferreds along with the setTimeout function to manage the response to the user.
I begin calling a function to display my loading message. I then use AJAX to retrieve the data. The success function then loops through the data sets and:
- Defines the current data set in a stat variable
- Invokes the loadDomElement function (see explanation below) which returns a promise
- Pushes the returned promise into my promises array
- Uses the .apply function to pass the promises array and when all promises have been done, it hides the loading block to reveal all of the elemens that have been loaded in the background.
$(function() {
displayMyWaiter('Fetching month end statistics for all pitches....');
$.ajax ( {
url: '../../ajax/stats.php',
method: 'GET',
data: {mode: 'all statistics for ent', statEntity: 'pitch', statType: 'total', statFilter: 'distinct'},
dataType: 'json',
type: 'POST',
success: function(statGroup){
console.log(statGroup);
var promises = [];
for (var i in statGroup) {
var stat = statGroup[i];
console.log(stat);
var def = $.Deferred();
$.when( loadDomElement(stat) ).done(function() {
console.log( "hello" );
def.resolve();
promises.push(def);
});
};
$.when.apply($, promises).done(function() {
hideMyWaiter("slide");
});
}
});
});
The loadDomElement function has the current stat passed to it as an argument and returns a promise. It essentially appends a html block to my page. It then invokes the loadStat function which also returns a promise - which resolves the deferred in the loadDomElement function. The code looks like this:
function loadDomElement(stat) {
var dfd = $.Deferred();
var statPanelID = 'stat_block_' + stat.code;
$('#stats').append( '<div id="' + statPanelID + '"></div>' );
$.when( loadStat(statPanelID, stat) ).done(function() {
dfd.resolve();
});
return dfd.promise()
}
The loadStat function begins by creating an outerDef deferred variable. It then invokes my function to update the message in the Loading block. This returns a promise:
function updateMyWaiter(str) {
var text = "<li class='waiter-item'>" + str + "</li>"
var dfd = $.Deferred();
setTimeout(function(){
$('.busyText').append(text);
dfd.resolve();
}, 3000);
return dfd.promise();
}
When the promise is returned it then invokes my panel function (which also returns a promise) and uses my custom plugin to load teh statistical data onto the page (behind the Loading message). The function looks like this:
function loadStat(statPanelID, stat) {
console.log("Now create stats for " + stat.code + ": " + stat.desc + " and place it in this block: " + statPanelID);
var outerDef = $.Deferred();
$.when( updateMyWaiter("Loading stats for " + stat.desc + "( code: " + stat.code + ")") ).done(function() {
var panel = function() {
var d = $.Deferred();
var panelTitle = (stat.desc === null ? 'Pitch ' + stat.code : stat.desc);
var statPluginID = 'stat_' + stat.code;
$("#" + statPanelID).panIt({
allowScrolling: false,
header: {
title: panelTitle
},
body: {
content: '<div id="' + statPluginID + '">Position stat plugin for ' + stat.desc + ' here.</div>',
height: '700'
},
onLoaded: function() {
$.when ( $('#' + statPluginID).stats({ // dom ID for stat plugin
statEntity: 'pitch',
statEntityID: stat.code,
statType: 'total',
statPeriod: null,
chartType: 'line',
chartTitle: 'Pitch stats for: ' + stat.desc,
activeTab: 'chart',
clickOptions: {
enabled: false
},
chartHeight: 700,
table: {
headers: [
{ name: 'Month', data: 'month' },
{ name: 'BF', data: 'bf' },
{ name: 'New', data: 'new_mem' },
{ name: 'Trn In', data: 'tra_in' },
{ name: 'Trn Out', data: 'tra_out' },
{ name: 'Lapsed', data: 'lapsed' },
{ name: 'CF', data: 'cf' },
{ name: 'Balance', data: 'balance'}
],
hasSelect: false,
search: false
}
})).done (function(result) {
d.resolve ('Pitch stats: ' + result);
});
}
});
return d.promise();
};
$.when ( panel() ).done (function(result) {
console.log(result);
outerDef.resolve(result);
});
});
return outerDef.promise();
}
I essentially want the application to begin with my intiail message: 'Fetching month end statistics for all pitches....' and then for each statistic it should update the loading message with anotehr line that says which statistic is now being loaded. Once all statistics have been loaded, the loading message should be hidden.
But what happens is that I get the intial message which is only displayed for a second before it is hidden. The applicaiton then proceeds to load the data to the DOM.