Reputation: 115
I have a set of custom user data that I want to make an ajax call to, and in the event that there is no user data, make another ajax call to retrieve a default set of data, and then execute a function after parsing the data. Here's an example:
var oData = [],
exampleUrl = 'example.php';
$.ajax({
url: exampleUrl + '?query=getUserData',
contentType: 'application/json;odata=verbose',
headers: {
'accept': 'application/json;odata=verbose'
},
success : function(data, request){
// Request succeeded
// Check the results
if(data.length){
// There are custom user results!
// Parse the results
oData = data;
}
else{
// There were no custom user results...
// Run another query to retrieve default values
$.ajax({
url: examplUrl + '?query=getDefaultData',
contentType: 'application/json;odata=verbose',
headers: {
'accept': 'application/json;odata=verbose'
},
success : function(data, request){
// Request succeeded
// Check the results
if(data.length){
// There was some default data!
// Parse the results
oData = data;
}
else{
// No data was found...
// Attempt to be helpful
console.log('No Default data was found!');
}
},
error : function(data, request){
// There was an error with the request
// Attempt to be helpful
console.log('Error retrieving data:');
console.log(data);
console.log(request);
}
});
}
},
error : function(data, request){
// There was an error with the request
// Attempt to be helpful
console.log('Error retrieving Custom User data:');
console.log(data);
console.log(request);
},
complete : function(){
// Do something with the data
index.displayData(oData);
}
});
The issue is that if the second ajax call is run, oData doesn't contain any data at all when it's passed to index.displayData()
. I'm guessing it has something to do with the asyncronous nature of ajax calls, but shouldn't 'complete' run after everything inside of 'success' runs?
I also know I probably shouldn't be using the ajax "Pyramid of Doom" and should be using promises, but I've tried them and keep getting the same results.
Thank you for your assistance!
Upvotes: 2
Views: 1063
Reputation: 19288
By working with promises, you can avoid the need to pass a callback into your function, and by defining a utility function you can avoid repetition of code.
//reusable utility function, which returns either a resolved or a rejected promise
function fetchData(queryString, cache) {
return $.ajax({
url: 'example.php',
data: { query: queryString },
type: 'JSON',//assumed
cache: cache,
contentType: 'application/json;odata=verbose',
headers: { 'accept': 'application/json;odata=verbose' }
}).then(function(data, textStatus, jqXHR) {
if (data && data.length) {
return data;
} else {
return $.Deferred().reject(jqXHR, 'no data returned').promise();//emulate a jQuery ajax failure
}
});
}
This allows promise methods to be used for a control structure, which :
//control structure
fetchData('getUserData', false).then(null, function(jqXHR, textStatus) {
console.log('Error retrieving Custom User data: ' + textStatus);
return fetchData('getDefaultData', true);
}).then(index.displayData, function(jqXHR, textStatus) {
console.log('Error retrieving default data: ' + textStatus);
});
Notes :
null
in .then(null, function(){...})
allows a successful response to drop straight through to the second .then(index.displayData, ...)
Upvotes: 1
Reputation: 69934
As pointed out by Violent Crayon, you could try calling "complete" yourself instead of relying on JQuery's implicit control flow:
function getData(exampleUrl, onComplete){
$.ajax({
success : function(data, request){
if(data.length){
onConplete(data);
}else{
$.ajax({
success : function(data, request){
if(data.length){
onComplete(data);
}else{
console.log('No Default data was found!');
}
},
error : function(data, request){
console.log('Error retrieving data:');
}
});
}
},
error : function(data, request){
console.log('Error retrieving Custom User data:');
}
});
}
var oData = [];
getData('example.php', function(data){
oData = data;
index.displayData(oData);
}
BTW, note how you can have your async functions receive their own return and error callbacks. This can help reduce the pyramid of doom problem without needing to use promises and without needing to hardcode the return callback.
Upvotes: 3