0

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 ?

M.Dietz
  • 900
  • 10
  • 29
  • Why update the `td` instead of having an `img` element with that class in your template already, and setting _its_ values? Also, don't use `alt="up"` for all four images: the alt attribute is for you to describe what the image represents so that accessibility tools can describe the image to users with partial or no vision. – Mike 'Pomax' Kamermans Mar 19 '21 at 17:04
  • you can look at this and add a `` inside your `` https://stackoverflow.com/questions/34504203/how-to-allow-html-in-return-of-angular2-pipe – rhavelka Mar 19 '21 at 17:07

2 Answers2

1

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

Bembem
  • 249
  • 4
  • 12
0

Unless you REALLY know what you're doing, avoid innerHTML at all costs as it very quickly can lead to XSS vulnerabilities, even if your direct fields don't lead to a visible XSS vulnerability. From a brief inspection, there is almost definitely a better way to do this, but hard to know without the actual code. I would suggest doing something like the following:

<td *matCellDef="let order" mat-cell>{someValue ? someValue : someOtherValue}</td>

Or separating it out into a function.

<td *matCellDef="let order" mat-cell>{MyComponent(order.statusForInterval)}</td>