0

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>
Bwizard
  • 955
  • 2
  • 15
  • 36

1 Answers1

1

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

Marshal
  • 10,499
  • 2
  • 34
  • 53
  • Great stuff. Thank you. I was just wondering how to dynamically set the style so that the tooltip always stays underneath the trigger component, as the list gets larger it does not stay underneath, The tooltip could have up to 10 items inside. – Bwizard Nov 12 '20 at 14:46
  • 1
    Actually I think I have an idea for this using ngStyle and a variable. Thanks for your swift answer. – Bwizard Nov 12 '20 at 14:53
  • I recommend creating a new question about vertical positioning of the tooltip; myself or someone will take a look at it... as this one is about displaying `person1` and `person2` in the tooltip – Marshal Nov 12 '20 at 14:55
  • Will do if I need to. Thanks again! – Bwizard Nov 12 '20 at 14:58
  • I added the styling question if you are interested. https://stackoverflow.com/questions/64807930/styling-viewcontainerref-from-directive-input-array – Bwizard Nov 12 '20 at 16:38