Peter Matisko
Peter Matisko

Reputation: 2253

Angular2 - Dynamic components in content received by API

I have a component . The content for this component is received by API and it contains another components .

The question is, how to render the child component. When I put the received content into innerHTML, the component tags are removed.

I checked all the articles about creating a component using resolveComponentFactory, but it seems this is a different case.

Upvotes: 2

Views: 1101

Answers (3)

Peter Matisko
Peter Matisko

Reputation: 2253

Using other answers and Gunter's hints here is what works for me:

@Component({
  selector: 'blog-app',
  template: `
  <h1> Article preview </h1>
  <div #container> </div>
  `
 })

export class BlogAppComponent {

@Input() content : string;

@ViewChild('container', { read: ViewContainerRef }) container: ViewContainerRef;


 constructor (private zone : NgZone, private compiler: Compiler ) {

 }  

 private addComponent(template: string) {
    @Component({template: template})
    class TemplateComponent {}

    @NgModule({declarations: [TemplateComponent], imports: [BlogAppModule]})
    class TemplateModule {}

    const mod = this.compiler.compileModuleAndAllComponentsSync(TemplateModule);
    const factory = mod.componentFactories.find((comp) =>
      comp.componentType === TemplateComponent
    );
    const component = this.container.createComponent(factory);
 }

 ngOnChanges(changes: SimpleChanges)  {

   this.zone.run(() => {
       this.addComponent(changes['content'].currentValue);
   });
 }
}

Upvotes: 2

G&#252;nter Z&#246;chbauer
G&#252;nter Z&#246;chbauer

Reputation: 657158

Even when you use the safeHtml pipe mentioned in @laser's answer, Angular doesn't process HTML added using innerHTML. It is just added as HTML and not processed any furter - no components or directives are created, no data binding or event binding will happen.

What you can do is to create a component at runtime with your HTML as template content and then add this component dynamically using ViewContainerRef.createComponent() and resolveComponentFactory

See also Equivalent of $compile in Angular 2

Upvotes: 1

laser
laser

Reputation: 570

Here is good solution with safeHtml directive: https://github.com/ngx-translate/core/issues/354

You create a directive:

import { Directive, ElementRef, Input, OnChanges, Sanitizer, SecurityContext,
  SimpleChanges } from '@angular/core';

// Sets the element's innerHTML to a sanitized version of [safeHtml]
@Directive({ selector: '[safeHtml]' })
export class HtmlDirective implements OnChanges {
  @Input() safeHtml: string;

  constructor(private elementRef: ElementRef, private sanitizer: Sanitizer) {}

  ngOnChanges(changes: SimpleChanges): any {
    if ('safeHtml' in changes) {
      this.elementRef.nativeElement.innerHTML =
        this.sanitizer.sanitize(SecurityContext.HTML, this.safeHtml);
    }
  }
}

and use it as following: <div [safeHtml]="'HELLO' | translate"></div>

Upvotes: 0

Related Questions