自作の構造ディレクティブを実装
次に、構造ディレクティブを自作する方法を説明します。
基本的な構造ディレクティブ
まず、単純な例として、合言葉が一致したときにメッセージを表示する構造ディレクティブを、図4のサンプルで説明します。
メッセージ表示部分の記述は、リスト13の通りです。myMatchKeywordディレクティブのパラメーターに、コンポーネント変数inputKeywordを設定しています。
<div *myMatchKeyword="inputKeyword"> <div>ディレクティブが指定された要素の内容です。</div> <div>合言葉に「Angular」と入力すると、この部分が表示されます。</div> </div>
ディレクティブの実装は、リスト14の通りです。
// コンストラクター ...(1) constructor( private templateRef: TemplateRef<any>, // 表示内容のテンプレート private viewContainer: ViewContainerRef // 表示する場所 ) { } // プロパティ @Input('myMatchKeyword') set myMatchKeyword(keyword: string) { // 現在の表示内容をクリア ...(2) this.viewContainer.clear(); // 条件に合致したときに、テンプレートからビューを生成して追加 ...(3) if (keyword === 'Angular') { this.viewContainer.createEmbeddedView(this.templateRef); } }
コンストラクター(1)で、表示内容のテンプレートを表すtemplateRefと、表示する場所を表すviewContainerを、依存性注入で受け取ります。プロパティのセッターでは、(2)のviewContainer.clearメソッドで表示内容をクリア後、(3)のviewContainer.createEmbeddedViewメソッドで、テンプレートから実際の表示内容(ビュー)を生成して表示場所に追加します。
ngForのような繰り返し指定を受け付けるディレクティブ
次に、ngForのように繰り返しの指定を受け付ける、図5のサンプルを説明します。OS(os)とスマートフォン名(name)を含むJavaScriptオブジェクトの配列から、OSが「iOS」のものを抽出して、スマートフォン名をリスト表示します。
リスト表示部分の記述はリスト15の通りです。ngForディレクティブと同様に、表示する配列を「let <配列の要素> of <配列>」形式で指定します。
<li *myPhoneFilter="let phone of phoneList">{{phone.name}}</li>
ディレクティブの実装は、リスト16の通りです。
// 「let phone of phoneList」のphoneListを引数に受け取るセッター ...(1) @Input('myPhoneFilterOf') set myPhoneFilterOf(inputValues: any[]) { this.viewContainer.clear(); // 現在の表示内容をクリア inputValues.forEach((value, input, array) => { if (value.os === 'iOS') { // テンプレートからビューを生成して追加 ...(2) this.viewContainer.createEmbeddedView(this.templateRef, { $implicit: value // $implicitは「phone」に対応 ...(3) }); } }); }
(1)のプロパティで、「let phone of phoneList」の「phoneList」配列を、セッターの引数inputValuesとして受け取ります。ここでポイントになるのはプロパティ名で、「let phone of phoneList」の「of」をディレクティブ名の後ろに付加した「myPhoneFilterOf」がプロパティ名になります。
受け取った配列要素の「os」が「iOS」の場合のみ、(2)でテンプレートからビューを生成して追加します。このとき、createEmbeddedViewメソッドの第2引数に、テンプレートに適用する変数をJavaScriptオブジェクトで指定します。(3)の$implicitは、「let A of B」のAに対応する変数で、ここでは配列の要素を代入します。その結果、リスト15では「{{phone.name}}」という記述で、スマートフォン名を表示できます。
まとめ
本記事では、要素の属性や構造を操作するAngularのディレクティブを取り上げて、自作ディレクティブの実装方法を説明しました。ディレクティブは、さまざまなHTML要素に適用できる共通の属性や処理を実装したい場合に便利です。また、これに関連して、ディレクティブを他のプロジェクトで再利用するときに便利なライブラリープロジェクトについて説明しました。
次回は、Googleが推進するデザインガイドライン「Material Design」をAngularで利用できる「Angular Material」について解説します。