SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

AngularJSではじめるJavaScriptフレームワーク開発スタイル

AngularJSのディレクティブ機能でHTMLテンプレートを使いこなそう

AngularJSで初めるJavaScriptフレームワーク開発スタイル 第6回

基本のディレクティブ

 データバインディング(データをテンプレート側に表示)をする際に必要な基本のディレクティブです。

モデルをテンプレートにバインドする基本のディレクティブ - ngBind

 ngBindはモデル(データ)をHTMLテンプレートバインドする基本的なディレクティブです。属性にng-bindとして指定する以外にも、{{式}}でも同様の表示ができるので、こちらを利用するケースが多くなるかと思います。

 しかしながら、要素のテキストとして指定した場合に一瞬ですが、{{式}}のテキストが表示されてしまうことがあります。属性に指定することで、この問題を回避できます。この問題を回避するには後述するngCloakを利用することで回避することもできます。

 また、あまり、オススメはできませんが、クラス名に「ng-bind:」とする事でも利用可能です。ただし、他のディレクティブでクラス名での指定が利用できるとは限らないので、属性で指定する方が好ましいでしょう。

リスト2 ngBindの使用例(ngbind.htmlの抜粋)
<div ng-init="hello = 'こんにちは'"></div>  <!-- 後述のngInitを参照 -->
<table>
    <tr><td>属性にモデルを記述した場合</td><td><span ng-bind="hello"></span></td></tr>
    <tr><td>class属性を使用した場合</td><td><span class="ng-bind: hello"></span></td></tr>
</table>
図1 ngBindの実行結果
図1 ngBindの実行結果

テンプレート形式でバインドするモデルを指定できるディレクティブ - ngBindTemplate

 ngBindTemplateは、テンプレート形式(=式以外の文字列を含んだ形式)を指定できるディレクティブです。

 ngBindとほぼ同様ですが、属性にテンプレート形式の記述方法でバインドできる点が異なります。

リスト3 ngBindTemplateの利用例(ngbind_teplate.htmlの抜粋)
<div ng-init="hello = 'こんにちは'"></div>
<p ng-bind-template="{{hello}} world!"></p>
<!-- 以下の指定と同じ結果が得られます -->
<p>{{hello}} world!</p>
図2 ngBindTemplateの実行結果
図2 ngBindTemplateの実行結果

記述した式の記述がちらつく現象を抑制するディレクティブ - ngCloak

 ngCloakモジュールは、リファレンスだけを見ていても少々分かりにくいディレクティブですが、実際にテンプレート機能を使っていると、表示上に、一瞬だけ"{{式}}"のように実際に記述した内容が見えてしまう場合があります。この問題は、先に述べたようにng-bindやng-bind-templateなどの属性を使って指定することでも回避できますが、ngCloakディレクティブを使うことでも回避できます。

リスト4 ngCloakの利用例(ngcloak.htmlの抜粋)
<div ng-init="hello = 'Hello'"></div>
<div ng-cloak>
    <p>{{hello}} World</p>
</div>

 このディレクティブはCSSを使って実現されていて、リスト5(ngCloakが使用しているCSSの定義)のCSSをAngularJSが自動で生成しています。テンプレートのパースが終了し、{{式}}の表示がされない工程になった時にngCloakが指定された要素を表示するようにすることでチラツキが起きないようにしています。

 従ってng-cloakをbody要素など表示全体に指定はしないほうが望ましいです。

リスト5 ngCloakが使用しているCSSの定義
[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
    display: none !important;
}

HTMLコードをテンプレートにバインドする - ngBindHtml

 ngBindHtmlはHTMLコードを含んだ文字列をHTMLのままバインドするためのディレクティブです。ngBindやngBindTempalteでは、危険なHTMLコードを含んだ文字列は自動的にエスケープされてしまいます。これは出力するHTMLを安全にするためのAngularJSの機能なのですが、意図的にHTMLを出力したいケースがあります。この場合にngBindHtmlを使うことで、安全にHTMLのコードをテンプレートにバインドできます。

 ngBindとngBindHtmlを使って「<a href='javascript:alert("click")'><b>Hello</b></a>」というコードをバインドしたコードと結果が、リスト6(ngBindHtmlの利用例)と図3(ngBindHtmlの実行結果)です。

リスト6 ngBindHtmlの利用例(ngbind_html.htmlの抜粋)
<table>
    <tr><td>ngBindの場合</td><td>{{helloHtml}}</td></tr>
    <tr><td>ngBindHtmlの場合(通常)</td><td><span ng-bind-html="helloHtml"></span></td></tr>
    <tr><td>ngBindHtmlの場合(trustAsHtml)</td><td><span ng-bind-html="helloTrustHtml"></span></td></tr>
</table>
図3 ngBindHtmlの実行結果
図3 ngBindHtmlの実行結果

 ngBindではエスケープされてしまっていますが、ngBindHtmlを使えばエスケープされずに出力されています。ngBindHtmlの出力例として(通常)と(trustAsHtml)と記載された物では表示が若干異なる事に気がついたでしょうか?

 この2つの違いはDOM上に構築されたHTMLコードを見ればすぐにわかります。リスト7(ngBindHtmlで生成されたHTMLコード)に注目してください。

リスト7 ngBindHtmlで生成されたHTMLコード
<a><b>Hello</b></a>
<a href='javascript:alert("click")'><b>Hello</b></a>

 この出力の違いを含めて、このディレクティブ機能を使うには若干の注意点がありますので、それらを含めて説明します。

 まず、このディレクティブを使うにはngSanitizeモジュールが必要でリスト8のように追加のJavaScriptソースを読み込む必要があります。

リスト8 ngSanitizeモジュールの組み込み
//(1)HTMLでの指定
<script type="text/javascript" src="vendors/angular-sanitize.js"></script>

//(2)AngularJSでngSanitizeモジュールを指定
var app = angular.module('app',['ngSanitize']);

 HTML側には(1)のようにangular-sanitize.jsもしくは、angular-sanitize.min.jsを読み込みます。続いて、(2)のようにmoduleメソッドにngSanitizeを指定するとモジュールの組み込みは終了です。

 コントローラ側の使い方はリスト9のようになります。

リスト9 コントローラ側でのngBindHtmlへのデータ設定
module.controller('ngBindHtmlController',['$scope','$sce',function($scope,$sce){
    var html = "<a href='javascript:alert(\"click\")'><b>Hello</b></a>";  // ・・・(1)
    $scope.helloHtml = html;                                       //・・・(2)
    $scope.helloTrustHtml  = $sce.trustAsHtml(html);  // ・・・(3)
}]);

 出力するHTMLコードは(1)のようなコードとします。(2)のようにそのままの設定にすると、先の(通常)出力となります。つまり、XSS等の危険性があるコードが削除されてしまいます。そのため、属性が除去されてタグの要素名とHelloという文字列だけになるので結果的に太字でHelloという見え方になります。

 ユーザが入力フィールドなどを通じてHTMLコードを部分的に登録するケースでは、これらの安全機能は非常に有効ですが、プログラマが意図的に記述したような場合にはこれでは問題があります。

 そこでHTMLコードが安全であることが保証できる場合には、(4)のようにtrustAsHtmlメソッドを使い、安全性をプログラマが保証すれば指定したコードがそのまま表示されます。このようにHTMLコードを扱うのは多少面倒ではありますが、一方で安全な利用ができるように考慮されています。

 この機能は$sceというサービスを利用しています。この"sce"は、Strict Contextual Escapingの略であり、コンテキスト(例えば、HTMLやJavaScriptなど)に応じてエスケープや出力を制限するための機能で、ここで紹介したHTMLコード以外の使い方もありますので詳しくはリファレンスを参照してください。

テンプレート内で変数の定義など、式の実行をするディレクティブ - ngInit

 ngInitは指定された式を実行するディレクティブです。今までのサンプルでも使ってきましたが、コントローラを通さずに値を設定したい場合などには有効な方法です。

リスト10 ngInitの利用例(nginit.htmlの抜粋)
<div ng-init="hello = 'こんにちは';">
    <span>{{hello}}</span>
</div>

次のページ
制御を扱うためのディレクティブ

この記事は参考になりましたか?

AngularJSではじめるJavaScriptフレームワーク開発スタイル連載記事一覧

もっと読む

この記事の著者

山田 祥寛(ヤマダ ヨシヒロ)

静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト」代表。主な著書に「独習シリーズ(Java・C#・Python・PHP・Ruby・JSP&サーブレットなど)」「速習シリーズ(ASP.NET Core・Vue.js・React・TypeScript・ECMAScript、Laravelなど)」「改訂3版JavaScript本格入門」「これからはじめるLaravel実践入門」「はじめてのAndroidアプリ開発 Kotlin編 」他、著書多数

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

WINGSプロジェクト 小林 昌弘(コバヤシ マサヒロ)

WINGSプロジェクト について> 有限会社 WINGSプロジェクト が運営する、テクニカル執筆コミュニティ(代表 ...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/8486 2015/03/17 14:00

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー