6

I am having a little trouble with binding a dynamic function to a click event. Please see below:-

File 1

<title-bar [actions]='[{title: "Create A New Plan", link: "hello"}]' ></title-bar>

File 2

<div class="actions" *ngIf="actions">
    <a *ngFor="let action of actions" class="ui primary button" (click)="[action.link]()">{{action.title}}</a>
</div>

All of the code is working perfectly apart from when I am binding the action.link in the (click).

If I create the following button:-

<button (click)="hello()"></button>

It calls the hello() function as it should. but for some reason I am not able to get this to work dynamically.

Does anybody have a simple solution to this I may have over looked?

The function is calling a simple alert just for testing:-

public hello() {
    alert('test');
}

II have attempted to change the click event to the following but with no joy:-

(click)="action.link"
(click)="[action.link]()"
(click)="this[action.link]()"

I get the following errors respectively:-

No error, but not function called
inline template:3:2 caused by: ["hello"] is not a function
inline template:3:2 caused by: self.parentView.parentView.context[self.context.$implicit.link] is not a function

Any help with a push in the right direction will be very much appreciated.

Tony Hensler
  • 1,482
  • 5
  • 15
  • 30

4 Answers4

13

In the component you need

get self() { return this; }

and in the template

<a *ngFor="let action of actions" class="ui primary button"
  (click)="self[action.link]()">{{action.title}}</a>

Use

<a *ngFor="let action of actions" class="ui primary button"
  (click)="this[action.link]()">{{action.title}}</a>
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • 1
    Would you be able to explain and elaborate on the "get self() { return this; }" function? – Tony Hensler Feb 17 '17 at 13:00
  • 2
    With `(click)="[action.link]()"` you create an array with one item `action.link` and apply a function call (which is not expected to work). With `(click)="self[action.link]()"` you reference the property with the name from `action.link` of the object returned by `self` which is the components class instance (which I assumed is what you want). `this` is not supported in the template AFAIK, so `self` is a workaround to make `this` available. – Günter Zöchbauer Feb 17 '17 at 13:03
  • Thank you for explaining, this work around works perfectly. – Tony Hensler Feb 17 '17 at 13:06
  • You're welcome. Glad to hear you could make it work :) – Günter Zöchbauer Feb 17 '17 at 13:07
  • 2
    `this` is now available in the template to refer to the component class, so the self getter is no longer required – danwellman May 21 '18 at 10:47
  • How would one pass arguments in the function call? – sparkyShorts Jan 24 '19 at 23:48
  • Like in TypeScript. Just pass it. Yoir question is not clear to me. Can you elaborate what you want to pass and for what purpose? – Günter Zöchbauer Jan 25 '19 at 04:21
  • Upgrading to Angular 9 appears to break this solution. With previously working code, I now get the following error... ERROR TypeError: "ctx_r355[Button_r353.click] is not a function" – AppDreamer Apr 05 '20 at 12:51
  • 1
    I just went back to your self example above and it now works in 9. I guess sometimes we have to go back a little to move forward? ;-) – AppDreamer Apr 05 '20 at 12:58
3

I needed to do something similar with ngFor. Accepted answer works but gave me a linting error: 'Call target is not callable'

There's another SO answer from Günter which helped me find a lint-error free solution : Angular2 passing function as component input is not working

My component.ts

this.myLinks = [
  {
    imgSrc: 'assets/a.png,
    clickFunction: this.aFn,
  },
  {
    imgSrc: 'assets/b.png,
    clickFunction: this.bFn,
  },
];


aFn() {
  console.log('function A');
}
bFn() {
  console.log('function B');
}

My template.html

<div *ngFor="let link of myLinks">
   <img
     [src]="link.imgSrc"
     (click)="link.clickFunction.apply(this)"
   />
</div>
Chris Newman
  • 3,152
  • 1
  • 16
  • 17
0

It worked for me like this:

(click)=self[action.link]()
0

Component.ts

items = [
  {
    name: 'share',
    action: this.share
  },
  {
    name: 'report',
    action: this.report
  }
];

share() {}
report() {}

Component.html

<el *ngFor="let i of items" (click)="i.action()"></el>
gr99t
  • 1