Yulian
Yulian

Reputation: 6769

How to assign an array when calling asynchronous functions?

I'm using AngularJS and Angular Translate. I have an array of objects that have 'key' property - a string that should be translated.

This is my array of objects:

var objects = [{
        id: 1,
        key: 'Jacket'
    }, {
        id: 2,
        key: 'Trousers'
    }, {
        id: 3,
        key: 'Hat'
    }];

These are my translations:

var translationsEN = { 
    Jacket: 'This is Jacket in English',
    Trousers: 'This is Trousers in English',
    Hat: 'This is Hat in English'
}

When some particular events occur I need an array of the objects but with the translations, not with the keys. That's why I have a function that does the following:

var translatedObjects = [];

for (var i = 0; i < objects.length; i++) {
    $translate(objects[i].key).then(function (translation) {
        translatedObjects[i] = translation;
    });
} 

After the function execution the result stored in the translatedObjects array is:

[null,null,null,"This is Hat in English"]

I guess that this is happening because I'm actually executing an asynchronous call to the $translate service and translatedObject[i] is not actually pointing to the right object, because 'i' is not defined in the current context.

So, how can I execute an asynchronous function call and assign my array appropriately as shown in the example above?

Upvotes: 0

Views: 89

Answers (3)

Shanoor
Shanoor

Reputation: 13682

You're already using promises so you can use Promise.all():

var promises = [];
for (var i = 0; i < objects.length; i++) {
    promises.push($translate(objects[i].key));
}

Promise.all(promises).then(function (translatedObjects) {
    // use your array here
});

Upvotes: 0

David Hedlund
David Hedlund

Reputation: 129802

Yes, the for loop will have completed and the value of i will be 3 when the callback fires. The three callbacks will then overwrite the value at the same index three times.

You can encapsulate your variable in a new scope:

for (var i = 0; i < objects.length; i++) {
    $translate(objects[i].key).then((function(x) { 
        return function (translation) {
           translatedObjects[x] = translation;
        };
    })(i));
} 

What happens above is you create an anonymous function that accepts a parameter, x, and returns a callback function. So when you call that function passing i=0, it will return a callback function which has access to x=0 from the scope in which it was created. At the next iteration, the anonymous function will be called again, and return a new callback function, where x is 1, etc.

If you know that the callbacks will be called sychronously, and assigning to an array is all you want to do, then ngLover's answer is probably more readable.

Upvotes: 1

ngLover
ngLover

Reputation: 4578

You can use push method of array to insert data . don't need to pass i since it will be inserted in same sequence.

for (var i = 0; i < objects.length; i++) {
    $translate(objects[i].key).then(function (translation) {
        $scope.translatedObjects.push(translation);
    });
} 

Upvotes: 1

Related Questions