So I have an Angular 8 app with a table that is displaying parsed XML content, but there are some cases where a string can contain
tags that needs to be parsed as HTML, but also other content braced in less/greater than signs, for example . I'm using [innerHTML] to inject it to a tag, but these braced strings get cut out. I've tried using DomSanitizer like this:
public sanitizeDsxText(text: any): any {
return this.sanitizer.bypassSecurityTrustHtml(text);
}
But unfortunately, that didn't work either. Have anyone ever faced a similar issue and can provide a simple solution? I will appreciate it greatly :),
EDIT: As per request, to be more precise. I have a like this:
<td class="dsx-table__cell" [innerHTML]="item.target?.txt">
</td>
Text in "item.target?.txt" looks like this:
"Cześć wam, tu bliźniaki dwa <br/> Paprika – siostra, brat <FAR/OFF>" *
And the <bt/>
get parsed like it should, to normal <br>
tag, but <FAR/OFF>
get cut out - I need to find a way to only parse <br>
's and leave other strings in brackets not parsed.
Yes, it's safe.
Angular automatically escapes data if you use ng-bind or the {{ curly brace syntax }} . This means it outputs the literal characters instead of interpreting them as HTML.
The innerHtml attribute is a standard HTML element attribute to which Angular 14 can bind with square brackets i.e [ & ] .
I'm late to the party. I've created a Angular pipe that either allows you to selectively allow tags or have the option to convert them to HTML entities.
Here's the code:
import { Pipe, PipeTransform } from "@angular/core";
import { DomSanitizer } from "@angular/platform-browser";
import DOMPurify from "dompurify";
@Pipe({
name: "safeHtml",
})
export class SafeHtmlPipe implements PipeTransform {
constructor(private domSanitizer: DomSanitizer) {
// How to securely allow target attribute
// https://github.com/cure53/DOMPurify/issues/317
DOMPurify.addHook("afterSanitizeAttributes", function (node: Element) {
// set all elements owning target to target=_blank
if ("target" in node) {
(node as Element).setAttribute("target", "_blank");
(node as Element).setAttribute("rel", "noopener");
}
});
}
transform(html: string, convertToEntity: boolean, additionalTags?: string[]): string {
if (html.length > 0) {
// we don't want tags such as `<input>` or any form elements
// from being displayed, and at the same time allows certain
// tags element for styling
const sanitizeOptions = {
FORBID_TAGS: ["script", "form", "input", "select", "textarea"],
ADD_TAGS: ["b", "i", "em", "span"],
ALLOW_UNKNOWN_PROTOCOLS: true,
// NOTE: we enable this one if in case the addHook method has unexpected behavior
// ADD_ATTR: ["target"],
};
if (additionalTags && additionalTags.length) {
sanitizeOptions.ADD_TAGS.push(...additionalTags);
}
let sanitizedContent = html;
if (convertToEntity) {
sanitizedContent = this.escapeHtml(html);
} else {
sanitizedContent = DOMPurify.sanitize(html, sanitizeOptions);
}
return this.domSanitizer.bypassSecurityTrustHtml(sanitizedContent) as string;
}
return html;
}
private escapeHtml(str: string): string {
// DOMSanitizer or DOMPurify doesn't have options to convert special characters
// to html entities
return str
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
}
}
Usage:
img
and a
tags<div class="modal-body" [innerHTML]="message | safeHtml: false:['img', 'a']"></div>
<p [innerHTML]="content | safeHtml: true"></p>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With