I would like to convert and replace all words in an array using a an object's method which returns an observable. The problem is that since the result is asynchronous, the value of result is overwritten incorrectly at the wrong index. If I had a synchronous function, I could have just simply call the function in a for loop. What should I do in this case?
for(let word in this.words){
var i = Object.keys(this.words).indexOf(word);
this.convertor.get(this.words[i].value).subscribe( (result) => {
this.words[i].value = result; //The value of i is incorrect
});
}
You could solve this with a plain function that you bind an extra argument to:
this.convertor.get(this.words[i].value).subscribe( function (i, result) {
this.words[i].value = result;
}.bind(this, i));
.bind()
returns a (new) function that will be like the function you apply bind
on, but will pre-determine a few things for when that function is actually called:
this
will then be set to what you pass to bind
in the first argument. Contrary to arrow functions, old-fashioned functions normally get their this
value by how the function is called -- that behaviour is not what you desire, and so it is a welcome feature of bind
;
Some of the arguments can be fixed upfront. Whatever other arguments you pass via bind
become the values of the first arguments of that function -- they are not determined by the actual call. In this case the value of i is passed, so the function will get that value as its first argument, no matter how it is called later.
Any other argument that is passed to the function at the moment of the call(back) will follow the previously mentioned arguments. In this case, the actual call will pass the value of result, and so the function should deal with two arguments: one provided by bind
, the other by the caller.
This solves your issue as you can pass on the correct value of i to each of the functions without losing the value of this
.