How to insert an HTML file with [innerHtml] and maintain Angular attributes

Asked

Viewed 2,605 times

6

In my Componente i receive an HTML in the form of String and use [innerHtml] to insert this HTML in the Component View.

Component:

test(){
    alert('Teste :D');
}

html_string = '<input type="button" (click)="test()">';

View:

<div [innerHtml]="html_string"></div>

The problem I’m facing is that the moment the page loads, it ignores the (click)="teste()". In the end it ends up staying in the element, already others that are direct in the View, at the end disappear of the element. And I do the validation with the sanitizer.

2 answers

6

Update 2

If you do not want to make use of library, you can use the class Compiler ( Note: Not to be confused with $compile of Angularjs )

Filing cabinet app.componentts.

import { Compiler, Component, Injector, NgModule, NgModuleRef, ViewChild, ViewContainerRef } from "@angular/core";

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  @ViewChild('testando', { read: ViewContainerRef }) _container: ViewContainerRef;
  constructor(private _compiler: Compiler, private _injector: Injector, private _m: NgModuleRef<any>) { }

  test() {
    alert('Teste :D');
  }

  ngAfterViewInit() {
    const html_string = '<input type="button" (click)="test()" value={{btnValue}}>';
    const tmpCmp = Component({ template: html_string })(class { });
    const tmpModule = NgModule({ declarations: [tmpCmp] })(class { });

    this._compiler.compileModuleAndAllComponentsAsync(tmpModule)
      .then((factories) => {
        const f = factories.componentFactories[0];
        const cmpRef = f.create(this._injector, [], null, this._m);
        cmpRef.instance.btnValue = 'CLIQUE!';
        cmpRef.instance.test = this.test;
        this._container.insert(cmpRef.hostView);
      })
  }
}

Filing cabinet app.component.html

<div #testando></div>

See working in stackblitz

The above example was adapted from the article: Here is what you need to know about Dynamic Components in Angular. ( Here’s what you need to know about dynamic components in Angular - Free Translation. )

Update 1

Doing a search on Google, found the library p3x-angular-Compile.

To use, just follow the steps:

  1. Import library into archive app.modulets.

    import { CompileModule} from 'p3x-angular-compile';
    
  2. Configure the module:

    @NgModule({
      imports: [ ... CompileModule],
      ...
    })
    
  3. Template code:

    <div *ngIf="true" 
      [p3x-compile]="html_string"
      [p3x-compile-ctx]="this" >
    </div>
    
  4. Use your component normally like this in the question, with the exception that events should be preceded by context.:

    html_string = `<input type="button" (click)="context.test('wmsouza')" value="CLIQUE AQUI!">`;
    
    test(nome) {
      alert(`Olá, ${nome}`);
    }
    

You can see it working in stackblitz


This is not possible, because the subclass DomSanitizer simply ignores, the solution would be to use the method addEventListener to register an event in the element.

import { Component, ChangeDetectorRef, ElementRef } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {

  html_string;

  constructor(private sanitizer: DomSanitizer, private elRef: ElementRef, private cdRef: ChangeDetectorRef) { }

  test = (nome) => {
    alert(`Olá, ${nome}`);
  }

  ngOnInit() {
    this.html_string = this.sanitizer.bypassSecurityTrustHtml('<input type="button" value="CLIQUE AQUI!">');
    this.cdRef.detectChanges();
    this.elRef.nativeElement.querySelector('input').addEventListener('click', _ => { this.test('wmsouza') }, false);
  }
}

See working in stackblitz

0

Very simple, use the $compile:

Put him in your app.controller:

app.controller('MainController', function($scope, $http, $rootScope, $compile) {

...

Do the APPEND of HTML like this:

var elementoHTML = document.getElementById("elemento");
angular.element(elementoHTML).html( $compile(response.data)($scope) );

Browser other questions tagged

You are not signed in. Login or sign up in order to post.