0

I'm creating a small game and I have a component that display the name of the weapon, let's called it "WeaponComponent". Next to the weapon name should appear some button that would allow the user to execute some actions such as "fire", "drop", reload", etc... However, these actions should not call the same code depending on how the component is used. For example, the "fire" action should act differently whether I attack a monster or another player. Note that this is just an example and more variables can influence the code to execute.

So far, I created Input properties for every action leveraging whether the action is shown or not, so I can, based on the location where the component is used, display or not the action (because I can't show the "drop in hangar" action if the player is not on a hangar for example).

Moreover, each action button will display a spinner icon until the action is completed. Indeed, most actions will make a server side call so I want to display a nice loading indicator.

As the code to execute when I click on an action depends on some variables, I'd like to pass to the component a function to execute when the button is clicked. So I did this:

@Input()
public unmountAction: (id: number) => void | Promise<void>;

...

public async unmount(ac: ActionComponent): Promise<void> {

    if (this.unmountAction) {
        await Promise.resolve(this.unmountAction(this.data.id));
    }

    ac.complete();
}

So I have an Input that accepts a function that returns nothing or a Promise and this function is called by "unmount", which is the function executed by the component when the action is clicked. The ac.complete() is just used to hide the loading indicator.

For the sake of clarity, let's call the caller component "CallerComponent".

The issue with this approach is the fact that the keyword "this" in the executed function is not the one of "CallerComponent" but the one of the "WeaponComponent".

I guess that most of you are about to click "answer" to tell me to use Output decorator instead of Input, however, this won't solve my issue. Indeed, "WeaponComponent" needs to know when the function is done executing, to hide the loading indicator. Therefore, I can't just emit on the "EventEmitter". Of course, I could, pass in the output method a reference to the "WeaponComponent" on which I could call a "done" method that would hide the loading indicator but I was wondering if there was a better solution than this.

ssougnez
  • 5,315
  • 11
  • 46
  • 79
  • Can you show us how you define the functions that you pass to `[unmountAction]`? – ConnorsFan Mar 17 '18 at 01:21
  • I don’t have access to my laptop right now but this is a regular typescript class function, pretty much like the `unmount` method shown in the OP. I’ll edit it when I can. – ssougnez Mar 17 '18 at 01:26
  • You could define these methods as arrow functions, to preserve `this`. Something like: `public customAction = (id: number) => { ... }`. – ConnorsFan Mar 17 '18 at 01:38
  • Possible duplicate of [How to access the correct \`this\` inside a callback?](https://stackoverflow.com/questions/20279484/how-to-access-the-correct-this-inside-a-callback) – ConnorsFan Mar 17 '18 at 01:40
  • Take also a look at [this answer](https://stackoverflow.com/a/39981813/1009922). – ConnorsFan Mar 17 '18 at 01:51
  • Cool, it works, thanks – ssougnez Mar 17 '18 at 10:46

0 Answers0