Search code examples
angularivy

Angular 9 with Ivy, problem when calling a function like this[function]()


I have a problem with Angular 9 and Ivy. I declared a simple component :

.html

<p>list : not working</p>
<button *ngFor="let act of actions" (click)="this[act]()">{{act}}</button>
<p>unique : working</p>
<button (click)="this[action]()">{{action}}</button>

.ts

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-new-comp',
  templateUrl: './new-comp.component.html',
  styleUrls: ['./new-comp.component.css']
})
export class NewCompComponent implements OnInit {

  action: string = "testAction";
  actions = ["testAction", "anotherTestAction"]

  constructor() { }

  ngOnInit(): void {
  }

  testAction() {
    console.log("ok");
  }

  anotherTestAction() {
    console.log("another ok");
  }
}

The point is to call functions generically (with a component abstraction for example, here is just a simple way to reproduce!) and the ngFor part doesn't work, with a javascript error when I click the buttons :

core.js:6210 ERROR TypeError: Cannot read property '15' of null
    at walkUpViews (core.js:4373)
    at nextContextImpl (core.js:4362)
    at Module.ɵɵnextContext (core.js:22001)
    at NewCompComponent_button_2_Template_button_click_0_listener (new-comp.component.html:2)
    at executeListenerWithErrorHandling (core.js:21915)
    at wrapListenerIn_markDirtyAndPreventDefault (core.js:21957)
    at HTMLButtonElement.<anonymous> (platform-browser.js:976)
    at ZoneDelegate.invokeTask (zone-evergreen.js:399)
    at Object.onInvokeTask (core.js:41762)
    at ZoneDelegate.invokeTask (zone-evergreen.js:398)

The "unique" part is working by the way, and when I deactivate Ivy compiler (tscongif.app.json / angularCompilerOptions / enableIvy: false), both cases are working.

Maybe I missed something, maybe it's an Ivy bug, so here I am to ask some help to understand!

This is the Git repo, for testing : https://github.com/sylro/ivy-component-inheritance

Thanks for all!


Solution

  • Because you get it as a string and there is no valid syntax for string (). You can try to create key: value pairs with the reference to the function

    export class NewCompComponent implements OnInit {
    
      actions = [ 
                  { name: "testAction", action: testAction },
                  { name: "anotherTestAction", action: anotherTestAction } 
                ];
    
      constructor() { }
    
      ngOnInit(): void {
      }
    
      testAction() {
        console.log("ok");
      }
    
      anotherTestAction() {
        console.log("another ok");
      }
    }
    

    And on the template have a code like

    <p>list : not working</p>
    <button *ngFor="let act of actions" (click)="act.action()">{{act.key}}</button>
    <p>unique : working</p>