Search code examples
angulardirective

How to add html tags in an Angular directive?


I got a tooltip directive that allows me to display a tooltip when hovering over an element.

However I would like in the text displayed in the tooltip to be able to integrate Html tags.

But the problem I am having is that the tags are considered to be text

enter image description here

Would there be a solution to integrate the html tags in the title of the tooltip ?

Here is the code :

app.component.ts

import { Component } from '@angular/core';

@Component({
selector: 'app-root',
template: `
<div class="tooltip-example" style="margin-top:100px">
   <div [tooltip]="displayStatut()" placement="top" delay="500">tootip on top</div>
 </div>
 `,
 styles: [`
.tooltip-example {
  text-align: center;
  padding: 0 50px;
 }
.tooltip-example [tooltip] {
  display: inline-block;
  margin: 50px 20px;
  width: 180px;
  height: 50px;
  border: 1px solid gray;
  border-radius: 5px;
  line-height: 50px;
  text-align: center;
}
.ng-tooltip {
  position: absolute;
  max-width: 150px;
  font-size: 14px;
  text-align: center;
  color: #f8f8f2;
  padding: 3px 8px;
  background: #282a36;
  border-radius: 4px;
  z-index: 1000;
  opacity: 0;
}
.ng-tooltip:after {
  content: "";
  position: absolute;
  border-style: solid;
}
.ng-tooltip-top:after {
  top: 100%;
  left: 50%;
  margin-left: -5px;
  border-width: 5px;
  border-color: black transparent transparent transparent;
}
.ng-tooltip-bottom:after {
  bottom: 100%;
  left: 50%;
  margin-left: -5px;
  border-width: 5px;
  border-color: transparent transparent black transparent;
}
.ng-tooltip-left:after {
  top: 50%;
  left: 100%;
  margin-top: -5px;
  border-width: 5px;
  border-color: transparent transparent transparent black;
}
.ng-tooltip-right:after {
  top: 50%;
  right: 100%;
  margin-top: -5px;
  border-width: 5px;
  border-color: transparent black transparent transparent;
}
.ng-tooltip-show {
  opacity: 1;
  }
 `]
 })

 export class AppComponent {

public displayStatut() {
let content;
content += "<ul style='margin-bottom:10px;text-align: left'><li>Test</li></ul>";
return content;
  }
}

tooltip.directive.ts

import { Directive, Input, ElementRef, HostListener, Renderer2 }
from '@angular/core';

@Directive({   selector: '[tooltip]' }) export class TooltipDirective
{   @Input('tooltip') tooltipTitle: string;   @Input() placement:
string;   @Input() delay: string;   tooltip: HTMLElement;   
tooltip 
offset = 10;

constructor(private el: ElementRef, private renderer: Renderer2) { }

@HostListener('mouseenter') onMouseEnter() {
if (!this.tooltip) { this.show(); }   }

@HostListener('mouseleave') onMouseLeave() {
if (this.tooltip) { this.hide(); }   }

show() {
this.create();
this.setPosition();
this.renderer.addClass(this.tooltip, 'ng-tooltip-show');   }

hide() {
this.renderer.removeClass(this.tooltip, 'ng-tooltip-show');
window.setTimeout(() => {
  this.renderer.removeChild(document.body, this.tooltip);
  this.tooltip = null;
}, this.delay);   }

create() {
this.tooltip = this.renderer.createElement('span');

this.renderer.appendChild(
  this.tooltip,
  this.renderer.createText(this.tooltipTitle) // textNode
);

this.renderer.appendChild(document.body, this.tooltip);
// this.renderer.appendChild(this.el.nativeElement, this.tooltip);

this.renderer.addClass(this.tooltip, 'ng-tooltip');
this.renderer.addClass(this.tooltip, `ng-tooltip-${this.placement}`);

// delay
this.renderer.setStyle(this.tooltip, '-webkit-transition', `opacity 
${this.delay}ms`);
this.renderer.setStyle(this.tooltip, '-moz-transition', `opacity ${this.delay}ms`);
this.renderer.setStyle(this.tooltip, '-o-transition', `opacity ${this.delay}ms`);
this.renderer.setStyle(this.tooltip, 'transition', `opacity ${this.delay}ms`);   }

 setPosition() {
const hostPos = this.el.nativeElement.getBoundingClientRect();

// tooltip
const tooltipPos = this.tooltip.getBoundingClientRect();

// window scroll top
// getBoundingClientRect 
viewport.
const scrollPos = window.pageYOffset || document.documentElement.scrollTop || 
 document.body.scrollTop || 0;

let top, left;

if (this.placement === 'top') {
  top = hostPos.top - tooltipPos.height - this.offset;
  left = hostPos.left + (hostPos.width - tooltipPos.width) / 2;
}

if (this.placement === 'bottom') {
  top = hostPos.bottom + this.offset;
  left = hostPos.left + (hostPos.width - tooltipPos.width) / 2;
}

if (this.placement === 'left') {
  top = hostPos.top + (hostPos.height - tooltipPos.height) / 2;
  left = hostPos.left - tooltipPos.width - this.offset;
}

if (this.placement === 'right') {
  top = hostPos.top + (hostPos.height - tooltipPos.height) / 2;
  left = hostPos.right + this.offset;
}
 
this.renderer.setStyle(this.tooltip, 'top', `${top + scrollPos}px`);
this.renderer.setStyle(this.tooltip, 'left', `${left}px`);   } }

https://stackblitz.com/edit/angular-tooltip-directive-fkawer


Solution

  • You use deprecated Renderer need to set InnerHTML to nativeElement like

    this.renderer.setElementProperty(el.nativeElement, 'innerHTML', this.tooltipTitle);
    

    Alternatively, if you use Renderer2, its

    this.renderer.setProperty(this.el.nativeElement, 'innerHTML', this.tooltipTitle);
    

    If tooltip content comes from external, you also need to use DomSanitizer

    this.sanitizer.bypassSecurityTrustHtml(content)