Reputation: 79
I have a need to make multiple concurrent calls to an Angular resource, and chain some actions with the $promise api.
I define a resource like this
myServicesModule.factory('MyResource', ['$resource', 'SETTINGS', function($resource, SETTINGS) {
return $resource(SETTINGS.serverUrl + '/myResource/:id', { },
{
get: { method: "get", url: SETTINGS.serverUrl + '/myResource/show/:id' },
}
);
}]);
My controller needs to retrieve multiple records, and take actions on each one when the record is ready. I am having trouble passing values to the then() closure.
When I do this:
for (var i = 0; i < 3; i++) {
MyResource.get({id: i}).$promise.then(function(item) { console.log(i); });
}
The output is "2, 2, 2".
This code results in the desired output of "0, 1, 2" (order varies depending on when each resource call completes), but this is an ugly solution.
for (var i = 0; i < 3; i++) {
var closure = function(i) {
return function(item) { console.log(i); console.log(item); }
}
UwgCarrier.get({id: i}).$promise.then( closure(i) );
}
Why does the first code snippet return "2, 2, 2" ?
Is there a cleaner way to solve this problem?
Upvotes: 0
Views: 482
Reputation: 4874
It's a matter of closures. Just wrap your closure in another one.
You can make a workaround with a call to an immediate function, that would look like :
for (var i = 0; i < 3; i++) {
(function(c) {
UwgCarrier.get({id: c}).$promise.then( console.log(c); );
})(i);
}
In my example I have replaced "i" by "c" into the closure to make things clear. Like so, the immediate function invoke "i" with its current value within the loop process.
I don't think that there is a better way to do this as it's a javascript concern.
EDIT :
As ES6 is coming soon, you can use the "let" keyword to achieve the same goal without wrapping your inner loop in a closure, because "let" block-scoped your variable.
for (let i = 0; i < 3; i++) {
UwgCarrier.get({id: i}).$promise.then( console.log(i); );
}
Upvotes: 1