7

Let's say i have CtrlOne that extends CtrlTwo, and a componentOne that instantiated in CtrlOne template. Some code (i'm skipping most of the irrelevant code just so the problem will be clearer):

class CtrlOne extends CtrlTwo {
    constructor() { super(); }
}

class CtrlTwo {

    sayMyName(name: string) {
        console.log(this.getMyLastName() + name);
    }

    getMyLastName() {
       return 'squarepants';
    }  
}

This is the template associated with CtrlOne:

<component-one data-say-my-name="vm.sayMyName"></component-one>

And this is stateless componentOne:

angular.module('mymodule').component('componentOne', {
     bindings: {
         sayMyName: '&'
     },
     template: '<button data-ng-click="$ctrl.sayMyName()('spongebob')></button>'
});

On click, i successfully get to the function sayMyName of CtrlTwo, but it's refusing to recognize this.getMyLastName , throwing TypeError: this.getMyLastName is not a function.

If i just use sayMyName or getMyLastName directly from CtrlOne template, everything works fine. But if i use it trough the binding passed to componentOne, i get the error.

What am i missing here?

jvrnt
  • 635
  • 1
  • 6
  • 20

1 Answers1

9

Class methods that are supposed to be used as callbacks should be bound to their context.

Like

class CtrlTwo {
    constructor() {
        this.sayMyName = this.sayMyName.bind(this);
    }
    ...
}

or

class CtrlTwo {
    sayMyName = (name: string) => { ... }
    ...
}
Estus Flask
  • 206,104
  • 70
  • 425
  • 565
  • Solved my issue, thank you! In case anyone is wondering how to pass parameters in this scenario, just tack them on to the end: `this.sayMyName.bind(this)(name);` – Kon May 21 '19 at 16:18
  • @Kon You're welcome. `bind` provides overhead because it creates a new function. If you don't need to reuse it, `call` is a better alternative. As for your scenario, there's no practical difference between `this.sayMyName.bind(this)(name)` and `this.sayMyName(name)`. There would be a difference if it wasn't called, `this.sayMyName.bind(this, name)` – Estus Flask May 21 '19 at 16:28
  • I have logic that determines at runtime which function needs to be called. Once I call X function, it loses `this` context inside that function (unlike if I call that function directly without assigning it to an alias/variable first). That's why I have to `X.bind(this)`. – Kon May 23 '19 at 16:59