Reputation: 6800
this is what I have:
function loadGraphs(datawijk){
$.ajax({
url: './api5.php', //the script to call to get data
data: {
wijk: datawijk,
}, //you can insert url argumnets here to pass to api.php
//for example "id=5&parent=6"
dataType: 'json', //data format
success: function(rows) //on recieve of reply
{
var htmlContent = "";
// ADD TO
htmlContent += '<tr><th scope="row">Geboortes</th>';
$.each(rows, function(i, data) {
$.each(data, function(j, year) {
htmlContent +=
'<td>' + year + '</td>';
});
});
htmlContent += '</tr>';
var lol = updateOverlijdens(datawijk, htmlContent);
alert(lol);
$('#graphs table tbody').html(htmlContent);
}
});
}
function updateOverlijdens(datawijk, htmlContent){
$.ajax({
url: './api4.php', //the script to call to get data
data: {
wijk: datawijk,
}, //you can insert url argumnets here to pass to api.php
//for example "id=5&parent=6"
dataType: 'json', //data format
success: function(rows) //on recieve of reply
{
// ADD TO
htmlContent += '<tr><th scope="row">Overlijdens</th>';
$.each(rows, function(i, data) {
$.each(data, function(j, year) {
htmlContent +=
'<td>' + year + '</td>';
});
});
htmlContent += '</tr>';
return htmlContent;
}
});
}
When I do alert(lol); in function loadGraphs I get undefined ... And when I do alert(htmlContent); in function updateOverlijdens just before I return the value I get it right. Only when I alert the value in my function loadGraphs I get undefined. How can I fix this?
Upvotes: 1
Views: 214
Reputation: 20159
As explained by a lot of answers, the problem is that you're trying to return something from the AJAX call back to the function which initiated the call. This cannot work, since the caller does not wait for the AJAX call to complete and will return before it is completed. That's the whole idea about asynchronous calls: you don't want to block the execution to wait for the results to come in.
One way to handle this is by passing a callback function which needs to be executed when the results are retrieved. This function will then be called from within the AJAX success callback.
Another interesting approach is to make use of jQuery's deferreds and promises. A promise represents some value which will be retrieved somewhere in the future. A deferred produces a promise and resolves it later on. For example, all AJAX functions return a promise and you can retrieve a promise from any jQuery object which is resolved when all animations are completed.
In your case, you can create a deferred which is resolved with the htmlContent
when the AJAX results are retrieved. You return the promise of that deferred from the function so the caller can bind callbacks to it or combine it with other promises.
function updateOverlijdens(datawijk) {
// Create the deferred
var dfd = new jQuery.Deferred();
// Initiate the AJAX request
$.ajax({
url: './api4.php',
data: {
wijk: datawijk,
},
dataType: 'json',
success: function(rows) {
var htmlContent = '<tr><th scope="row">Overlijdens</th>';
$.each(rows, function(i, data) {
$.each(data, function(j, year) {
htmlContent += '<td>' + year + '</td>';
});
});
htmlContent += '</tr>';
// Resolve the deferred
dfd.resolve(htmlContent);
},
error: function() {
// An error occurred, reject the deferred
dfd.reject();
}
});
// Return a promise
return dfd.promise();
}
BEGIN EDIT
Thanks to Benjamin Gruenbaum for pointing out my usage of the deferred anti-pattern. Here's an implementation using .then
to do the chaining:
function updateOverlijdens(datawijk) {
return $.ajax({
url: './api4.php',
data: {
wijk: datawijk,
},
dataType: 'json'
}).then(function(rows) {
var htmlContent = '<tr><th scope="row">Overlijdens</th>';
$.each(rows, function(i, data) {
$.each(data, function(j, year) {
htmlContent += '<td>' + year + '</td>';
});
});
htmlContent += '</tr>';
return htmlContent;
});
}
END EDIT
You can then use the promise in your loadGraphs
AJAX success callback like so:
// Produce the table header
var htmlContent = '<tr><th scope="row">Geboortes</th>';
$.each(rows, function(i, data) {
$.each(data, function(j, year) {
htmlContent += '<td>' + year + '</td>';
});
});
var promise = updateOverlijdens(datawijk);
promise.then(function(htmlOverlijdens) {
// Append to the previously created HTML content
htmlContent += htmlOverlijdens;
// Apply the HTML
$('#graphs table tbody').html(htmlContent);
});
The advantage of using promises is that they give caller much more flexibility. The caller can easily register multiple callbacks using then()
, combine it with other promises using jQuery.when()
or pipe the results to another promise using pipe()
then
.
Upvotes: 1
Reputation: 276286
The reason you are getting undefined is that you are not returning anything from updateOverlijdens
(but from the inner function in success)
You are running asynchronous code, generally you can't solve this problem easily using the current function return pattern you are using since the data will not be available at the time of the return. What you need are callbacks.
Please see this page for good usage examples of jQuery ajax. What you'll be wanting to do is pass a function to updateOverlijdens and call it when the success callback of your ajax fires. There are plenty of examples for that online (and in the link above).
Here for example is your code after being modified to the correct callback pattern which addresses the problem it had with asyncrhonous execution
function loadGraphs(datawijk){
$.ajax({
url: './api5.php', //the script to call to get data
data: {
wijk: datawijk,
}, //you can insert url argumnets here to pass to api.php
//for example "id=5&parent=6"
dataType: 'json', //data format
success: function(rows) //on recieve of reply
{
var htmlContent = "";
// ADD TO
htmlContent += '<tr><th scope="row">Geboortes</th>';
$.each(rows, function(i, data) {
$.each(data, function(j, year) {
htmlContent +=
'<td>' + year + '</td>';
});
});
htmlContent += '</tr>';
updateOverlijdens(datawijk, htmlContent,function(lol){
alert(lol);
$('#graphs table tbody').html(lol);
});
}
});
}
function updateOverlijdens(datawijk, htmlContent,callback){
$.ajax({
url: './api4.php', //the script to call to get data
data: {
wijk: datawijk,
}, //you can insert url argumnets here to pass to api.php
//for example "id=5&parent=6"
dataType: 'json', //data format
success: function(rows) //on recieve of reply
{
// ADD TO
htmlContent += '<tr><th scope="row">Overlijdens</th>';
$.each(rows, function(i, data) {
$.each(data, function(j, year) {
htmlContent +=
'<td>' + year + '</td>';
});
});
htmlContent += '</tr>';
callback(htmlContent)
}
});
}
Upvotes: 4
Reputation: 111
Yes. There no mistake. You need to have return value for your function definied not in $.ajax. In your code you returning value to $.ajax, not to updateOverlijdens. Right code need to be:
function updateOverlijdens(datawijk, htmlContent){
$.ajax({ ....})
return 'some value'
}
Upvotes: 0