2

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.

Peter Matisko
  • 2,113
  • 1
  • 24
  • 47
  • if you mean [innerHtml] directive, then you probably need to use safehtml filter in angular 2. Check this: http://stackoverflow.com/questions/38577347/how-do-i-manually-sanitize-in-angular2 – laser Feb 13 '17 at 23:25

3 Answers3

2

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);
   });
 }
}
Peter Matisko
  • 2,113
  • 1
  • 24
  • 47
1

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

Community
  • 1
  • 1
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • I am not sure how to add the component. There might be one or more anywhere in the content. I tried creating and adding a component into a
    and it worked fine. But my issue is a bit more complicated.
    – Peter Matisko Feb 14 '17 at 09:57
  • You just need to create a component **at runtime** like explained in the linked answer above, that contains your whole HTML including the component selectors. When the component is created, the child components will be created automatically as well (if they are all registered in the modules `directives: [...]` parameter). You then only need to add the dynamically created component yourself. – Günter Zöchbauer Feb 14 '17 at 10:02
0

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>

laser
  • 570
  • 4
  • 20