9

I'm attempting to inject a string that contains a (click) event into the Angular2 template. The string is dynamically retrieved from the back-end much after the DOM is loaded. No surprise here that Angular won't recognize the injected (click) event.

Example template:

<div [innerHTML]="test"></div>

Example string given from back-end:

var test = "When ready, <span (click)=\"itemClick($event)\">click me</span>."

Example function call in the Angular component:

itemClick(event) {
   debugger;
}


My next guess would be to try having Angular subscribe or catch a plain-old javascript event, so the string would then be:
var test = "When ready, <span onClick=\"itemClick($event)\">click me</span>."

Sure enough, I get an error that itemClick is not defined, so I know it's looking for that javascript function.

So question: How can I get Angular2 to subscribe to this event or function?

Mark Rajcok
  • 362,217
  • 114
  • 495
  • 492
Rhyeen
  • 127
  • 1
  • 1
  • 5

1 Answers1

20

Declarative event binding is only supported in static HTML in a components template.
If you want to subscribe to events of elements dynamically added, you need to do it imperatively.

elementRef.nativeElement.querySelector(...).addEventListener(...)

or similar.

If you want to be WebWorker-safe, you can inject the Renderer

constructor(private elementRef:ElementRef, private renderer:Renderer) {}

and use instead

this.renderer.listen(this.elementRef.nativeElement, 'click', (event) => { handleClick(event);});

to register an event handler.

see also Dynamically add event listener in Angular 2

Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • 1
    I would just like to add that since the above code is executed inside a component (as evidenced by the fact that Günter is using ElementRef and/or Renderer), it is executed inside the Angular zone, hence after the click event handler fires, Angular change detection will always run (as desired). (If you were to instead attach the event handler outside Angular, it would not work as desired.) – Mark Rajcok Mar 21 '16 at 15:58
  • Do we need to unregister the listener in `ngOnDestroy()` if we use `addEventListener()` or `listen()`? – Mark Rajcok Mar 22 '16 at 19:36
  • I assume - yes, but I'm never sure about this. Usually if you request a resource imperatively, you're responsible to release to be on the safe side. – Günter Zöchbauer Mar 22 '16 at 20:20
  • Apparently `Renderer.listen()` will return a function that will remove the listener (that's handy). See Eric's answer for an example: http://stackoverflow.com/a/35082441/215945 – Mark Rajcok Apr 27 '16 at 21:31
  • Thank you! I am getting exact same issue and I am not quiet clear how to add a listener for click event on a specific span . For example the one asked in the question. – user911 May 19 '17 at 15:05
  • Just replace `...` in `elementRef.nativeElement.querySelector(...).addEventListener()` with a CSS selector that matches the element - like `'span'` – Günter Zöchbauer May 19 '17 at 15:08
  • what is `e` mentioned there? – blackdaemon Jun 07 '17 at 08:47
  • @blackdaemon it should be `event`. Thanks for the hint - fixed. – Günter Zöchbauer Jun 07 '17 at 08:56
  • https://stackoverflow.com/questions/44407771/how-to-bind-a-click-event-function-in-innerhtml-angular-2?noredirect=1#comment75814579_44407771 – blackdaemon Jun 07 '17 at 08:59
  • @MarkRajcok so, is there a need to unregister them in ngOnDestroy() – Zaker Sep 10 '17 at 10:06
  • This won't work when you have duplicate generated html for example close buttons on thumbnails. – Techno Cracker Dec 20 '17 at 02:09