AngularテンプレートでinnerHTMLとDomSanitizerを使う方法
tinymceのようなプラグインで作成したコンテンツはHTMLコードとしてデータベースに保存されます。このHTMLをAngularテンプレートで安全にレンダリングする方法を整理します。
データベースに保存されたHTMLコードが次のようなものだと仮定します。
<h1><span style="color: #f1c40f;">こんにちは。イ・サンヒです。</span></h1>最もよくある間違いは、次のようにHTMLコードをタグの中にそのまま挿入する方法です。
<div class="post-content">{{ post.content }}</div>このように記述すると、下の画像のようにHTMLコードがそのままテキストとして出力されます。

この問題は次のようにinnerHTMLプロパティバインディング(property binding)を使うことで解決できます。
<div class="post-content" [innerHTML]="post.content"></div>
HTMLコードは正しくレンダリングされますが、別の問題が発生します。開発者ツールで実際に適用されたコードを確認すると、次のようにspanタグに含まれていたインラインCSSスタイルが取り除かれています。

この挙動は、Angularが危険なHTMLコードのDOMへの挿入を防ぐために提供している組み込みの保護機能によるものです。コンテンツが信頼できることを明示する必要があり、Angularが提供するDomSanitizerクラスで簡単に処理できます。
まずテンプレートで使用するパイプクラスを生成します。
$ ng g pipe trust-htmltrust-html.pipe.tsが生成されたら、次のコードのように修正します。
import { Pipe, PipeTransform } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';
@Pipe({
name: 'trustHtml'
})
export class TrustHtmlPipe implements PipeTransform {
constructor(private sanitizer: DomSanitizer) {
}
transform(content): unknown {
return this.sanitizer.bypassSecurityTrustHtml(content);
}
}app.module.tsのdeclarationsに登録するのも忘れずに行います。
import { TrustHtmlPipe } from './pipes/trust-html.pipe';
@NgModule({
declarations: [
AppComponent,
... 省略 ...
TrustHtmlPipe,
],生成したパイプをテンプレートで使うと、次のようになります。
<div class="post-content" [innerHTML]="post.content | trustHtml"></div>
以上で、innerHTMLプロパティバインディングとパイプ(pipe)クラスを活用して、データベースに保存されたHTMLをAngularテンプレートで安全にレンダリングする方法を整理しました。