【Angular】innerHTMLにバインドしてHTMLを動的に生成する方法!

Angularでは、データバインドを活用するとビューにHTMLを動的に反映させることができます。

この記事では『innerHTMLを用いて動的にHTMLを生成する方法』をサンプルコードを用いてわかりやすく解説します。

基本のデータバインド

Angularのデータバインドは安全性を重視して設計されています。例えば、以下のサンプルコードを見てみましょう。

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  template: '<p>{{ message }}</p>',
})
export class AppComponent {
  message: string = `
    <p>こんにちは!!</p>
    <script>alert("スクリプトです");</script>
    <a href="#" onclick="alert('リンクをクリックしました')">リンクです</a>
    <button onclick="alert('ボタンをクリックしました')">ボタンです</button>
    <font color="blue">青色のテキストです</font>
  `;
}

実行結果

基本のデータバインド

上記のサンプルコードでは、messageにHTMLタグを含む文字列を指定していますが、ビューでは文字列としてそのまま表示されます。AngularはデフォルトでHTMLをエスケープ処理するため、スクリプトやタグが実行されることはありません。

あわせて読みたい

エスケープ処理』とは、プログラミング言語やマークアップ言語で文字列を扱う際に、その言語によって特別な意味を持つ文字や記号(特殊文字)を通常の文字として扱うための処理、または逆に通常の文字を特別な意味を持つものとして扱うための処理のことです。

例えば、HTMLではタグの記述に<>という記号を使用します。これらの記号を文字列で使うと、Webブラウザはタグの記述であるとみなすため、表示することができません。そこで、これらの記号を表示する際には、<;&ltに、>;&gtに置き換えられています。この処理をエスケープ処理といいます。

エスケープ処理』については下記の記事で詳しく説明しています。興味のある方は下記のリンクからぜひチェックをしてみてください。

innerHTMLでHTMLを動的に生成する

動的に生成したHTML文字列をHTMLとして表示したい場合、innerHTMLに文字列をバインドします。以下にサンプルコードを示します。

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  template: '<div [innerHTML]="message"></div>',
})
export class AppComponent {
  message: string = `
    <p>こんにちは!!</p>
    <script>alert("スクリプトです");</script>
    <a href="#" onclick="alert('リンクをクリックしました')">リンクです</a>
    <button onclick="alert('ボタンをクリックしました')">ボタンです</button>
    <font color="blue">青色のテキストです</font>
  `;
}

実行結果

innerHTMLでHTMLを動的に生成する

この場合、[innerHTML]を使用しているため、messageの内容はHTMLとして解釈されて表示されます。しかし、Angularはセキュリティ上危険とみなした要素(例: <script>要素やイベントハンドラー付きの属性)は自動的に除去(サニタイズ)します。上記のサンプルコードの場合、<script>要素やonclick属性、<button>要素などが除去されています。

あわせて読みたい

サニタイズ』については下記の記事で詳しく説明しています。興味のある方は下記のリンクからぜひチェックをしてみてください。

サニタイズを回避する方法

HTML文字列が安全であることを保証できる場合は、DomSanitizerクラスのbypassSecurityTrustHtmlメソッドを使用すると、サニタイズを回避できます。以下にサンプルコードを示します。

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

@Component({
  selector: 'app-root',
  template: '<div [innerHTML]="safeMessage"></div>',
})
export class AppComponent {
  safeMessage: SafeHtml;
  message: string = `
    <p>こんにちは!!</p>
    <script>alert("スクリプトです");</script>
    <a href="#" onclick="alert('リンクをクリックしました')">リンクです</a>
    <button onclick="alert('ボタンをクリックしました')">ボタンです</button>
    <font color="blue">青色のテキストです</font>
  `;
  constructor(private sanitizer: DomSanitizer) {
    // サニタイズを回避するが、開発者がこのデータの安全性を保証する必要がある
    this.safeMessage = this.sanitizer.bypassSecurityTrustHtml(this.message);
  }
}

実行結果

innerHTMLでHTMLを動的に生成する(サニタイズを回避する方法)

DomSanitizerbypassSecurityTrustHtmlメソッドを使うことで、Angularが自動的に行うサニタイズを回避できます。これにより、スクリプトやイベントハンドラーなどもそのまま適用されます。なお、bypassSecurityTrustHtmlメソッドの戻り値(safeMessageプロパティ)の型はSafeHtmlです。

注意点

  • bypassSecurityTrustHtmlを使用する場合、開発者がそのHTML文字列が安全であることを保証しなければなりません。
  • 信頼できないデータをそのままバインドすると、XSS(クロスサイトスクリプティング)攻撃のリスクがあります。外部APIやユーザー入力からのデータには特に注意が必要です。

本記事のまとめ

この記事では『innerHTMLを用いて動的にHTMLを生成する方法』について、以下の内容を説明しました。

  • Angularのデフォルト動作
    • AngularではデフォルトでHTML文字列をエスケープ処理し、安全性を確保します。
  • innerHTMLを使用する方法
    • [innerHTML]を使うことで、文字列をHTMLとして解釈して表示できます。
    • ただし、Angularはセキュリティ上危険な要素(例: <script>タグ、onclick属性など)は自動で除去(サニタイズ)します。
  • サニタイズを回避する方法
    • DomSanitizerbypassSecurityTrustHtmlメソッドを使用すると、サニタイズを回避できます。
    • サニタイズを回避する際は、HTMLの安全性を開発者が保証する必要があります。

お読み頂きありがとうございました。