0

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?

3
  • for loop wont wait for the unsync operation to get complete. Commented Nov 20, 2015 at 7:37
  • Yes, and what can I do to achieve the result that I expected? Commented Nov 20, 2015 at 7:37
  • with recursive call to a function you can achieve it. Commented Nov 20, 2015 at 7:42

3 Answers 3

1

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.

Sign up to request clarification or add additional context in comments.

Comments

1

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);
    });
} 

3 Comments

Is the order of translated strings is guaranteed here? What if the first call to $translate() takes more time than the second?
@ShanShan ya shaan if $translate does and async task then david method of using closures is correct one.
I prefer my Promise.all solution though, cleaner and less nesting but OP made his choice :D
0

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
});

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.