0

Using [innerHTML] property to add the received content from server, if the appended HTML has (click) (onClick) or i'm supposing any other script tag they don't function when the HTML is inserted.

Supposing:

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

and in component.ts

element: string = "";
this.http.get....subscribe((data) => { // Some http call
    element = "<div id="element" (click)="console.log("something")"> data </div>"
})

Even though element shows properly the click function on it does not work. I've tried doing it with adding event listener after the element variable is assigned new value but that doesn't seem to be the moment html DOM is changed. so the event binder this.elementRef.nativeElement.querySelector('#element').addEventListener('click', this.onClick.bind(this)); throws error since it can't find the element. I don't know when the HTML is changed. So I can't use this inside ngAfterViewInit either.

What is the workaround here? and how do people normally add such dynamic html with javascript inside them anyway? looking for best practices.

Edit: I'm looking for an Angular approach and wanna know how such elements are handled in the framework by Angular developers. If not then Javascript, I'm not using JQuery library.

Swrena
  • 310
  • 3
  • 12
  • in jQuery you can do `$(document).on('click', '#id', function)` – full-stack Feb 21 '23 at 21:59
  • Does this answer your question? [Event binding on dynamically created elements?](https://stackoverflow.com/questions/203198/event-binding-on-dynamically-created-elements) – full-stack Feb 21 '23 at 22:01
  • Use an angular component rather, it is more versatile – Bart Feb 21 '23 at 22:09
  • @Bart If you can elaborate and add an answer with that approach and example code. (It needs to be something that uses the data received by http call as data.) I'll appreciate it and approve your answer. – Swrena Feb 22 '23 at 01:50
  • the answer is there is no way your code is compiled from template to javascript and now you are saying you want it to compile the templates you include even then angular team has to bring the compiler back client side. so silly – Tachibana Shin Feb 22 '23 at 01:59
  • @TachibanaShin How exactly is it silly? It's such a simple task. All I expect my frontend framework to do is apply onclick to an element that is added dynamically. does no one do this? if not then I need to know what they do instead. since this should be very common. hence the question about best approach. Calling my question silly makes no sense when you are not presenting any solution. – Swrena Feb 22 '23 at 07:42

1 Answers1

1

Important Note you need always use DomSanitizer to use innerHTML

constructor(private sanitizer: DomSanitizer) {}

//in any place
this.innerHtml = this.sanitizer.bypassSecurityTrustHtml(this.text);

All you use in a innerHtml should be "javaScript not related with your component", e.g. your text should be <div onclick="alert('hello')> else you need add a listener looking for the "div" and use addEventListener... puf!

Better you can add a click event to the div and check about target

<div (click)="click($event)" [innerHTML]="innerHtml"></div>

  click(event: any) {
    const target = event.target;
    const id = target.getAttribute('id');
    switch (id) {
      case 'element1':
        alert('Element 1');
        break;
    }
  }

This make that we need "re-thinking" the app. E.g. you can think use an attribute data-function in your text

text="<div id='element2' data-function='doSomething'>Element</div>"

And

   switch (id) {
      ...
      case 'element2':
        this[target.getAttribute('data-function')]();
        break;
    }
  }

  doSomething() {
    alert("I'm from Angular");
  }

A stackblitz

Eliseo
  • 50,109
  • 4
  • 29
  • 67
  • thank you, thorough explanations. Just what I needed. though all I needed to do was using the dom sanitizer instead of just assigning it and it works. made too much fuss for that :P. – Swrena Feb 22 '23 at 08:51