Reputation: 3442
I'm trying to set up a loop of Ajax calls and a function that runs after all the Ajax calls have resolved. I read through a bunch of SO questions on this problem and thought I was able to apply it to my code, but it isn't working and I can't for the life of me figure out why.
Here's the JS code. The map function
runs 10 times FYI.
function addData(data) {
var deferreds = [];
$.map(data, function(job) {
deferreds.push(addLocation(job));
});
console.log(deferreds);
$.when.apply($, deferreds).then(mapData(data));
}
function addLocation(job) {
var dfd = $.Deferred(),
url = url;
console.log('in the addLocation function, outside the ajax call');
$.ajax({
url: url,
dataType: 'jsonp',
jsonp: 'json_callback'
}).done(function(location) {
job.lnglat = [parseFloat(location[0].lon), parseFloat(location[0].lat)];
console.log('resolved location');
dfd.resolve();
});
return dfd.promise();
}
function mapData(data) {
console.log('in the mapData function');
console.log(data);
var point = svg.selectAll('points')
.data(data);
point.exit().remove();
point.enter().append('circle')
.attr('r', 2.5);
point
.attr('cx', function(d) {
console.log(d); //shows d and has the lnglat but I think that is due to the developer tools reading the final result, not the result at the time
console.log(d.lnglat); // this gives undefined
console.log(d.lnglat[0]); // this gives an error as it hasn't been defined
console.log(projection(d.lnglat[0]));
return projection(d.lnglat[0])[0];
})
.attr('cy', function(d) {
return projection(d.lnglat[1])[1];
});
}
The Chrome Developer tools reports the following order:
in the addLocation function, outside the ajax call //x10
[Object, object...] //this is the object list of deferred objects, there are 10 of them
in the mapData function
[Object, object..] //this is the object list of data from the mapData function
Object > ... //this is the d object in the mapData function > point anonymous function
undefined // this is the result of d.lnglat
Uncaught typeError ... // this is the result of d.lnglat[0] which doesn't exist yet
resolvedLocation //x10 this should be a lot higher right?
So I want the resolvedLocation console.log
to run prior to the in the mapData function
to run and I thought I had set it up that way, but it obviously isn't working. What am I missing?
Upvotes: 0
Views: 54
Reputation: 762
As adeneo said in his comment, the problem here is the imidiate invocation of mapData in
$.when.apply($, deferreds).then(mapData(data))
To solve this you need to use bind to keep most of you solution intact (and not change it much). This should work:
$.when.apply($, deferreds).then(mapData.bind(this, data))
The bind does not delay the invocation of the function. It binds the data argument to the invocation of the function, so when 'then' function invokes mapData, it does so with 'data' as its argument, and that happens only after all promises are resolved.
Upvotes: 1