Reputation: 603
I am working on function that calculates a distance from a given object to a number of other places with the help of Google Distance Matrix which is of course async therefore I'm dealing with promises.
When the number of places is one, everything works great. But once I have more than one promise, $q.all doesn't do anything : it neither resolves in a success nor in error. Though I have checked in the console that the calls to the Google distance matrix do happen and return a correct result. Any clue what can be at play here?
I am using AngularJS 1.6.4. Let me know should you need any more details. Thanks!
var requests = [];
for (var i = 0; i < ctrl.places.length; i += 1) {
var deferred = $q.defer();
requests.push(deferred.promise);
var destination = ctrl.places[i].latLng;
service.getDistanceMatrix({
origins: [ctrl.origin],
destinations: [destination[0] + "," + destination[1]],
travelMode: 'DRIVING'
}, function(response, status) {
if (status === 'OK') {
deferred.resolve(response.rows[0].elements[0].distance.text);
}
});
}
$q.all(requests).then(function(result) {
ctrl.distances = result;
});
Upvotes: 2
Views: 624
Reputation: 2512
Your problem is that var
is not block-scoped, so the value of deferred
will always belong to the final iteration of your loop by the time any of your callbacks are invoked. A consequence of this will that the earlier deferred will never be resolved and the $q.all
will appear to hang.
The simplest way to resolve this is to change your use of var
to let
to take advantage of block scoping:
let deferred = $q.defer();
Upvotes: 2
Reputation: 2851
Reason why it does not work
By the time the service call resolves and the callback handler is invoked, the deferred
attribute is referring to the very last deferred object created by the for
loop. So, in effect, you are always performing a resolve
on the very last deferred
object that was created.
Solution:
Create a new function:
function getDistanceMatrixForDestination (destination, origins) {
var deferred = $q.defer();
service.getDistanceMatrix({
origins: [origins],
destinations: [destination[0] + "," + destination[1]],
travelMode: 'DRIVING'
}, function(response, status) {
if (status === 'OK') {
deferred.resolve(response.rows[0].elements[0].distance.text);
} else {
deferred.reject();
}
});
return deferred.promise;
}
Change your existing code to this:
var requests = [];
for (var i = 0; i < ctrl.places.length; i += 1) {
var destination = ctrl.places[i].latLng;
requests.push(getDistanceMatrixForDestination (destination, ctrl.origins));
}
$q.all(requests).then(function(result) {
ctrl.distances = result;
});
Upvotes: 1