[Fixed] Is there any way to make tooltips work via innerHTML?

Issue

I am using the attribute innerHTML to edit the inner html of a tag, in this example of <td></td>, but it could be anything:

<td *matCellDef="let order" mat-cell [innerHTML]="order.statusForInterval | statusIcon"></td>

order.statusForInterval is a number and as you can see im calling the pipe statusIcon to return a string which then is binded to innerHTML. The pipe looks like this:

@Pipe({name: 'statusIcon'})
export class StatusIconPipe implements PipeTransform {
  transform(statusId: number) {
    switch (statusId) {
      case 0:
        return `<img class="status-icon" src="assets/svg/status-icon/open_icon.svg" alt="up" matTooltip="Open">`;
      case 1:
        return `<img class="status-icon" src="assets/svg/status-icon/progress_icon.svg" alt="up" matTooltip="Progress">`;
      case 2:
        return `<img class="status-icon" src="assets/svg/status-icon/checked_icon.svg" alt="up" matTooltip="Checked">`;
      case 3:
        return `<img class="status-icon" src="assets/svg/status-icon/booked_icon.svg" alt="up" matTooltip="Booked">`;
      case 4:
        return `<img class="status-icon" src="assets/svg/status-icon/error_icon.svg" alt="up" matTooltip="Error">`;
    }
  }
}

So depending on the number i return a string containing an img tag which then is binded to innerHTML.
All works as expected. The only problem i have is that the tooltips aren“t working when i use the innerHTML attribute. The attribute matTooltip="Open" is ignored if i set innerHTML this way.

Is there any way to make the tooltips work using innerHTML ?

Solution

I suggest you use two pipes. One for the image src and the other for the matToolTip. Something like

    <td mat-cell *matCellDef="let element">
      <img
        class="status-icon"
        [src]="element.position | tdImgSrc"
        alt="up"
        [matTooltip]="element.position | tdMatTooltip"
      />
      {{element.position}}
    </td>

Pipe for Image Src

import { Pipe, PipeTransform } from "@angular/core";

@Pipe({
  name: "tdImgSrc"
})
export class TdImgSrcPipe implements PipeTransform {
  transform(statusId: number): string {
    switch (statusId % 3) {
      case 0:
        return `https://img-authors.flaticon.com/freepik.jpg`;
      case 1:
        return `https://www.flaticon.com/svg/vstatic/svg/68/68858.svg?token=exp=1616188223~hmac=6ef8123fc9aa7d33aaeddbe4dea787b6`;
      case 2:
        return `https://www.flaticon.com/svg/vstatic/svg/68/68792.svg?token=exp=1616188228~hmac=36273c59084428c6005d1f361cfb27f7`;
      // case 3:
      //   return `assets/svg/status-icon/open_icon.svg`;
      // case 4:
      //   return `assets/svg/status-icon/open_icon.svg`;
    }
  }
}

Pipe for MatToolTip

import { Pipe, PipeTransform } from "@angular/core";

@Pipe({
  name: "tdMatTooltip"
})
export class TdMatTooltipPipe implements PipeTransform {
  transform(statusId: number): string {
    switch (statusId % 5) {
      case 0:
        return "Open";
      case 1:
        return "Progress";
      case 2:
        return "Checked";
      case 3:
        return "Booked";
      case 4:
        return "Error";
    }
  }
}

The advantage of this breakdown is that your code will be easy to read and maintain because each pipe has a single responsibility.

You can see the code on stackblitz here -> https://stackblitz.com/edit/angular-x9sdnn?file=app/table-basic-example.html

Leave a Reply

(*) Required, Your email will not be published