javascriptangularangular-directiveangular-component-life-cycle

angular directive load component inside my new div created instead of outside


I have various tooltips, so I decided to load them using directive. it works fine. But the thing is it's not loading inside the host or appended div. without loading the component with created child div, I am finding no use.

any one please help me?

here is my directive:

import { DOCUMENT } from '@angular/common';
import {
  Directive,
  ElementRef,
  Input,
  OnInit,
  SimpleChanges,
  HostListener,
  ViewContainerRef,
  Renderer2,
  Inject,
  ViewChild,
  ComponentFactoryResolver,
} from '@angular/core';
import { ComponentLoaderService } from './component-loader.service';

export interface LoaderConfig {
  componentName: string;
  action: string;
}
@Directive({
  selector: '[appComponentLoader]',
})
export class ComponentLoaderDirective implements OnInit {
  @Input() loaderConfig: LoaderConfig;

  private _loaderActive = false;

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

  constructor(
    private componentLoader: ComponentLoaderService,
    private elementRef: ElementRef,
    private renderer: Renderer2,
    @Inject(DOCUMENT) private document,
    private vr: ViewContainerRef,
    private componentFactoryResolver: ComponentFactoryResolver
  ) {}

  ngOnInit() {
    // this.loaderConfig.action = 'mouseenter'
    let child = document.createElement('div');
    child.style.border = '1px solid red';
    this.renderer.appendChild(this.elementRef.nativeElement, child); //my child should hold component
  }

  ngOnChanges(changes: SimpleChanges) {
    console.log('recived component name:', this.loaderConfig.action);

    // this.embedComponent();
  }
  @HostListener('mouseenter') mouseover() {
    if (this.loaderConfig.action === 'mouseenter') {
      this.embedComponent();
    } else {
      return;
    }
  }

  @HostListener('mouseleave') mouseleave() {
    if (this.loaderConfig.action === 'mouseenter') {
      this.removeComponent();
    } else return;
  }

  @HostListener('click') onClick() {
    if (this.loaderConfig.action === 'click') {
      this.toggleLoader();
    } else {
      return;
    }
  }

  embedComponent() {
    const componentRef = this.componentLoader.loadComponent(
      this.loaderConfig.componentName
    );
    if (componentRef) {
      this.vr.clear();
      this.vr.createComponent(componentRef); //just appending outside somewhere
    }
  }

  removeComponent() {
    this.vr.detach();
  }

  toggleLoader() {
    this._loaderActive = !this._loaderActive;
    if (this._loaderActive) {
      this.embedComponent();
    } else {
      this.removeComponent();
    }
  }
}

how can i load the component inside of my created child? thanks in advance


Solution

  • You can simply move dynamically rendered component's host element inside directive's host.

    this.vr.clear();
    const ref = this.vr.createComponent(componentRef); //just appending outside somewhere
    this.renderer.appendChild(this.elementRef.nativeElement, ref.location.nativeElement);
    

    Ng-run Example