angularangular-directiveangular-renderer2

Sending Data to an Angular Tooltip Directive


I have found an example online of a Tooltip directive. I need to expand it so I can pass data to the tooltip and render it in an *ngFor. So far I have

app.component.html

<div tooltipDirective [tooltipDataArray]="['Person1', 'Person2']">See tooltip!
  <ng-template #tooltipTemplate>      
      <div class="tooltip">   
          This is my tooltip!
      </div>      
  </ng-template>  
</div>

tooltip.directive.ts

  @Input() tooltipDataArray: string[];

  @ContentChild( "tooltipTemplate" ) private tooltipTemplateRef: TemplateRef<Object>;

  @HostListener('mouseenter')  onMouseEnter(): void { 
    console.log(this.tooltipDataArray);   
    const view = this.viewContainerRef.createEmbeddedView(this.tooltipTemplateRef);
    view.rootNodes.forEach(node => 
      this.renderer.appendChild(this.elementRef.nativeElement, node));
  }


  @HostListener('mouseleave') onMouseLeave(): void {        
    if (this.viewContainerRef) {
      this.viewContainerRef.clear();
    }  
  }  

I can log the data so it is being received but I am not sure how the createEmbeddView, rootNodes and appendchild work (I am working from an example). What I would like is the tooltip to contain Person1, Person2 one above the other. How would I make that possible?

StackBlitz Here

EDIT:

I thought trying this would get me closer to what I want and explain it better but now the tooltip does not show at all. Is this the correct way to go with this?

<div tooltipDirective [tooltipDataArray]="['Person1', 'Person2']">See tooltip!
 <ng-template #tooltipTemplate>      
   <div class="tooltip" *ngFor="let person of tooltipDataArray">
      {{ person }}
   </div>      
 </ng-template>  
</div>

Solution

  • One way you could accomplish this is by doing the following.

    Loop through your array and construct div elements and add them to the div.tooltip in the rootNodes of the view

      this.tooltipDataArray.forEach(el => {
          const child = document.createElement("div");
          child.innerText = el;
          this.renderer.appendChild(view.rootNodes[1], child);
        });
    

    Then loop through the nodes on the view and add them to the elementRef as you are doing now.

    view.rootNodes.forEach(node =>{
          this.renderer.appendChild(this.elementRef.nativeElement, node);
         } );
    

    STACKBLITZ

    https://stackblitz.com/edit/angular-zr2ydx?file=app/tooltip.directive.ts