Reputation: 11
I feel foolish for asking something so trivial, but I really want the best-practices answer (I'm not looking for a "setTimeout" solution unless nothing else is possible -- though I doubt that is the case).
The quick over-view: I have an array which I want to push to from within a callback. After I've populated the array I then want to use it, outside of the callbacks.
The practical use: I have an array of cities, I want to geocode them with Google's API and populate an array with all of the resulting LatLng's. Later I will create marker objects with them, add them to a clusterer, whatever.
coder = new google.maps.Geocoder();
$places = ['Truro, NS', 'Halifax, NS', 'Sydney, NS', 'Dartmouth, NS'];
all_the_pins = Array();
for(i in $places){
var $place = $places[i];
coder.geocode({address:$place}, function(res, stat){
switch(stat){
case 'OK':
all_the_pins.push(res[0].geometry.location);
break;
}
});
}
console.log(all_the_pins);
EDIT: to clarify the issue:
The problem isn't a question of scope or whether or not the all_the_pins
variable is global or not, if you were to examine all_the_pins
within the callback you will see that it is the same variable (which is being pushed to). The problem is that because the pushes happen within the callback they don't happen before the console.log
is run below.
Upvotes: 1
Views: 129
Reputation: 664766
No, setTimeout is absolutely useless in here. If you have several asynchronous requests, and want to do something when all of them called back, the only possibility is a counter. After the last callback the number of open requests will be down to null; then execute what you want.
var coder = new google.maps.Geocoder();
var places = ['Truro, NS', 'Halifax, NS', 'Sydney, NS', 'Dartmouth, NS'];
var all_the_pins = [];
for (var i=0; i<places.length)
coder.geocode({address:places[i]}, function(res, stat){
if (stat == 'OK')
all_the_pins.push(res[0].geometry.location);
else
all_the_pins.push(stat);
// counter is length of results array:
if (all_the_pins.length >= places.length) {
console.log(all_the_pins);
}
});
Upvotes: 1
Reputation: 707606
Since your question is not clear, I'll hazard a guess that you want to process the all_the_pins array
when all your geocode calls are done. Because the geocode function call is asynchronous, you have to keep track of when all geocode calls have completed and then you can use the final array.
If so, you can do that like this:
var coder = new google.maps.Geocoder();
var $places = ['Truro, NS', 'Halifax, NS', 'Sydney, NS', 'Dartmouth, NS'];
var all_the_pins = Array();
var remaining = $places.length;
for (var i = 0, len = $places.length; i < len; i++)
var $place = $places[i];
coder.geocode({address:$place}, function(res, stat){
switch(stat){
case 'OK':
all_the_pins.push(res[0].geometry.location);
break;
}
--remaining;
if (remaining == 0) {
// all_the_pins data is set here
// call a function and pass the array to it or put your
// code here to process it
console.log(all_the_pins);
}
});
}
Note: I also changed to the proper type of for
loop for iterating an array. for (var i in xxx)
is for iterating properties of an object, not elements of an array.
Upvotes: 1
Reputation: 11383
Can the rest of your code live inside another callback? I would set up a function that only executes after being called x number of times (i.e. the length of your input array).
coder = new google.maps.Geocoder();
$places = ['Truro, NS', 'Halifax, NS', 'Sydney, NS', 'Dartmouth, NS'];
all_the_pins = Array();
function myCallback(count, totalCount, all_the_pins) {
if (count != totalCount) return;
console.log(all_the_pins);
}
count = 1;
for(i in $places){
var $place = $places[i];
coder.geocode({address:$place}, function(res, stat){
switch(stat){
case 'OK':
all_the_pins.push(res[0].geometry.location);
myCallback(count, $places.length, all_the_pins);
count++;
break;
}
});
}
Upvotes: 0