user1938143
user1938143

Reputation: 1184

Angular can not render generated HTML with Button dynamically

I am facing a problem, I want to render generated HTML code, into material table with Pipe, but it is not working.

the code looks like this:

pipe.ts

import { Pipe, PipeTransform } from "@angular/core";
import * as _ from "underscore";

@Pipe({ name: "customPipeChecks" })
export class CustomPipeChecks implements PipeTransform {
  transform(
    elementValue: {},
    elementProperty: string,
    object: {},
    customPipeFunction: any,
    defaultValue: string
  ) {
    if (customPipeFunction != null && _.isFunction(customPipeFunction)) {
      console.log(customPipeFunction(elementValue, elementProperty, object));
      return customPipeFunction(elementValue, elementProperty, object);
    } else {
      if (defaultValue) {
        return defaultValue;
      }
      return elementValue;
    }
  }
}

the generated function

  private setCustomValueFunction() {
    this.customValueFunction = (
      elemValue: string,
      elemKey: string,
      elem: {}
    ) => {
      if (elemKey === "vin") {
        elemValue = "<button>zrdzdrz</button>";
      }
      return elemValue;
    };
  }

this function generates a HTML string.

the HTML code looks like this :


<td
     mat-cell
     *matCellDef="let cellData"
     class="{{
              cellData[colName]
                | customPipeChecks: colName:cellData:customCssFunction:' '
            }}"
     innerHtml="{{
              cellData[colName]
                | customPipeChecks: colName:cellData:customValueFunction
       }}">
</td>

When the app is loaded, it will shown only 'zrdzdrz' only the text (inner HTML of the desired button), without the button (that is suppoused to wrap the text).

Any suggestion?

Best Regards,

Leo

Upvotes: 1

Views: 453

Answers (1)

Very interesting question.

Here is a demo at StackBlitz that will fix your problem.

The reason why your implementation doesn't work is because angular is sanitizing the injected HTMl, in order to bypass this, your custom pipe should look like the snippet bellow, where the important part is the usage of DomSanitizer which will "tell" the framework in explicit manner that you want to inject HTML that must be rendered.

import { Pipe, PipeTransform } from "@angular/core";
import {
  DomSanitizer,
  SafeHtml
} from '@angular/platform-browser';

@Pipe({ name: "customPipeChecks" })
export class CustomPipeChecks implements PipeTransform {

  constructor(
    public sanitizer: DomSanitizer,
  ) { }
  transform() {
    return this.sanitizer.bypassSecurityTrustHtml('<button>Button content</button>')
  }
}

Update

One more notable point is that in the template you must inject the innerHTML in the following manner, [innerHTML]

<td mat-cell *matCellDef="let element" [innerHtml]="'someString' | customPipeChecks">
    </td>

Upvotes: 2

Related Questions