0

I am currently going through the Angular tutorial and came across the following code:

getHero(id: number): Promise<Hero> {
    return this.getHeroes().then( heroes => heroes.find( hero => hero.id === id ));
}

Out of curiosity, I decided to rewrite the callback function using a normal function:

getHero(id: number): Promise<Hero> {
    return this.getHeroes().then( heroes => heroes.find( this.findHero, id));
}

findHero(hero: Hero, index: number, array: Hero[]): boolean {
    if(hero.id === this.id){
        return true;
    }else{
        return false;
    }
}

But this gives me the error Property 'id' does not exist on type 'HeroService'.

How may I refer to the id parameter passed to my callback function?

1 Answer 1

2

The id (number) property is defined as an argument of the function getHero, thus, is not available in your function findHero. You tried to use this.id but the compiler is telling you that such a property does not exits in your class HeroService, which is correct of course, as if you wanted to have that property as part of your service then you would have to do something like this in your getHero method.

getHero(id: number, ...etc) {
    this.id = id;
    // etc.
}

However, that would bring you another problem: as your method getHeroes seems to be async code (I can tell because it is returning a Promise) this approach will cause you headaches with concurrency problems when your method getHero is called twice (or more times) from different parts of the application. The first getHero call will set this.id to x but in the meantime, while the async code is run, another call to getHero will set it to y, making that the callback findHero run in response to the first call use an incorrect value for the id(specifically, it will read y as the value for this.id).

So... long story short. You would probably want to read more about CLOSURES and why they are so important for JavaScript. Short answer to your question, use this:

getHero(id: number): Promise<Hero> {
    return this.getHeroes().then( heroes => heroes.find(this.findHero.bind(this, id));
}

And define your callback findHero as

findHero(idToFind: number, hero: Hero, index, array: Hero[]) {
    return hero.id === idToFind;
}

The reason why you need this is that the this is not passed automatically to the functions that you use as arguments for other functions (or methods, as in this case). So by using bind you explicitly BIND the this of such a function so that whenever you use this in findHero it points to the right object. The second argument of bind is binding the id you are looking for to every call of the function findHero, so that whenever the function returned by bind is called it happens two things:

  1. The this is bound to HeroService.
  2. Along with the arguments the function would normally receive, you are also binding another argument that will be automatically injected into the arguments of calls to that function.

Just one minor note... you are using TypeScript, so the this argument in your bind is pointless, as TypeScript automatically binds all methods in your class to the current instance, but you need it in this case because you also want to bind the second argument (the id to find).

I hope it I helped.

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

3 Comments

Hello @damianmr, thank you for your informative comment, it was helpful indeed. I had a look on closures here: developer.mozilla.org/en-US/docs/Web/JavaScript/Closures I've learned much from it. There is just one point I had to change in the code you provided. The parameters for the findHero function had to be written in this order: findHero(idToFind: number, hero: Hero, index: number, array: Hero[]): boolean{ I am not sure why and so currently googling for an answer. Thanks,
Found out why. Arguments for bind are prepended to the bounded function: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… Thanks,
@kiseragi I'll update the answer, I wrote it from my memory and thought it was added to the end :)

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.