Angular2 – Inject Component to the Body

Question:

Good evening!

I have the following component

import { Component, Input, ElementRef, HostListener, OnDestroy, OnInit } from '@angular/core';
/**
 * This class represents the navigation bar component.
 */

@Component({
  moduleId: module.id,
  selector: 'sd-notification',
  templateUrl: 'notification.component.html',
  styleUrls: ['notification.component.css'],
})
export class NotificationComponent implements OnDestroy, OnInit {

  constructor(private el: ElementRef) { }

  @Input() mensagem: string;
  @Input() time: number = 2000;
  @Input() tipo: string ="";
  isVisible = true;
  ngOnInit() {
    setTimeout(() => {
      this.ngOnDestroy();
    }, this.time);
  }

  ngOnDestroy() {
    this.isVisible = false;
    setTimeout(() => {
      this.el.nativeElement.remove();
    }, 1000);
  }

  private _timeOut: number = 3000;
  public get timeOut(): number {
    return this._timeOut;
  }
  public set timeOut(v: number) {
    this._timeOut = v;
  }

  fechar() {
    this.ngOnDestroy();
  }
}

I want to inject it into another Component, in javascript it would be something like this:

import { Component } from '@angular/core';
/**
 * This class represents the lazy loaded ServicoComponent.
 */
@Component({
  moduleId: module.id,
  selector: 'sd-servico',
  templateUrl: 'servico.component.html',
  styleUrls: ['servico.component.css']
})
export class ServicoComponent {

  constructor(public service: ServicoService) {
  }

  salvar(servico?: Servico) {
    document.body.innerHTML += '<sd-notification tipo="syo-success" mensagem="Dados salvos com sucesso!"></sd-notification>'; // Mas isso não compila a diretiva ds-notification.... 
  }

}

But with Angular2 it doesn't compile this directive.

Answer:

Well, for you to inject this component into another one, it is necessary to use an angular2 feature that can be seen in detail in this link on the official website.

To compile the component you must use the createComponent method of the ViewContainerRef class contained in '@angular/core'. This method receives as a parameter a ComponentFactory<T> which can be obtained in the following ways:

1 – Method resolveComponentFactory of the ComponentFactoryResolver class ('@angular/core') which receives as parameter the type of the component, in your case it would be NotificationComponent .

2 – Using some of the methods present in the Compiler class ('@angular/core'), being more common to use the compileModuleAndAllComponentsAsync which receives as parameter the module of the component to be "injected".

In summary, we can say that the ViewContainerRef would be a reference of the place where you will inject the component using one of the two ways presented above. You can see how it would look using ComponenteFactoryResolver in the example below:

export class InjetorComponent implements AfterViewInit, OnDestroy {

  constructor(private _componentFactoryResolver: ComponentFactoryResolver, private _vcRef: ViewContainerRef) { }

  ngAfterViewInit() {
    this.loadComponent();
  }

  ngOnDestroy() {
      //Destrói todas as views injetadas neste componente.
      this._vcRef.clear();
  }

  loadComponent() {
    let componentFactory = this._componentFactoryResolver.resolveComponentFactory(NotificationComponent);
    let componentRef = this._vcRef.createComponent(componentFactory);
    //Acessando a instancia do componente.
    (<NotificationComponent>componentRef.instance).menssagem = "Menssagem de um componente criado dinamicamente!";
  }
}

Some references with content about the subject (links from stackoverflow.com).

How do I dynamically inject an Angular2 sub component via typescript code?

How can I use/create dynamic template to compile dynamic Component with Angular 2.0?

Scroll to Top