Deep Insider の Tutor コーナー
>>  Deep Insider は本サイトからスピンオフした姉妹サイトです。よろしく! 
AngularJS TIPS

AngularJS TIPS

ディレクティブを自作するには?(directiveメソッド)

2016年9月14日

AngularJSで、ビューの操作/生成を独立させて独自ディレクティブを作成する基本的な定義方法と使用例を説明する。

  • このエントリーをはてなブックマークに追加

 本連載で紹介してきたように、AngularJSには標準でも汎用的なディレクティブが用意されています。しかし、実践的なアプリ開発には、標準的なディレクティブだけでは事足りない場合も少なくありません。そのような場合であっても、安易にコントローラーやサービスから文書ツリーを操作するのは避けるべきです。ビューとコントローラー/サービスとが密に絡み合うことでコードの見通しが悪化する、ユニットテストを実施しにくくなる、などの問題があるためです。

 ビューの操作/生成は、まずはディレクティブとして独立させるのが基本です。本稿では、ディレクティブを自作するためのdirectiveメソッドについて解説していきます*1

  • *1 AngularJS 1.5では要素型のディレクティブを定義するためのcomponentメソッドも追加されていますが、本稿では1.4以前の環境も考慮してdirectiveメソッドを優先して利用します。componentメソッドについては、後日別途解説の予定です。

[Note]拡張ディレクティブ(ライブラリ)について

 AngularJSの世界では、さまざまな拡張ディレクティブも提供されています。使われることが多い機能であれば、すでに提供されている可能性が高いので、まずは既存のライブラリを検索してみるのも良いでしょう。拡張ディレクティブ(ライブラリ)に関する詳細は、拙著『AngularJSライブラリ 活用レシピ 厳選 108』(Kindle版)などの専門書も参照してください。

 では、まずはごく基本的なwg-helloディレクティブを定義してみます。<wg-hello>要素で「こんにちは、世界!」という文字列を出力するだけの、ごく基本的なディレクティブです。

HTML
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<meta charset="UTF-8" />
<title>AngularJS TIPS</title>
</head>
<body ng-controller="MyController">
<!-- 5wg-helloディレクティブの呼び出し-->
<wg-hello></wg-hello>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.min.js"></script>
<script>
angular.module('myApp', [])
  // 1ディレクティブを定義
  .directive('wgHello', function() {
    // 2ディレクティブを定義するためのオブジェクトを返す
    return {
      // 4ディレクティブの適用箇所を指定
      restrict: 'E',
      // 3テンプレートを埋め込み
      template: '<p style="background-color:Yellow">こんにちは、世界!</p>'
    }
  })

  .controller('MyController', ['$scope', function($scope) {
  }]);
</script>
</body>
</html>
wg-helloディレクティブを定義するためのコード(directive.html)
テンプレートで指定された文字列が表示される
テンプレートで指定された文字列が表示される

 ディレクティブを定義するには、directiveメソッドを利用します(1)。

[構文]directiveメソッド

directive(name, factory)

  • name: ディレクティブの名前
  • factory: ディレクティブを生成するファクトリー関数

 引数nameには正規化された名前(「[Note]正規化された名前」参照)を指定します。また、他のディレクティブ、またはHTML標準の要素/属性とバッティングしないようにするためにも、何らかの名前空間を接頭辞として付与しておくことをお勧めします。この例であれば、「wg」がそれです(この「wg」は、筆者が所属しているコミュニティ「WINGSプロジェクト」に由来しています)。名前空間は、タイプの簡便さを考慮して、差し支えない範囲で短い名前とするのが無難でしょう。また、AngularJS標準の「ng」は利用すべきではありません。

[Note]正規化された名前

 AngularJSでは、以下のような手順でディレクティブ名を正規化しています。

  • 先頭の「x-」「data-」を除去
  • 「-」「_」「:」で区切られた名前をcamelCase形式に変換

 よって、x-wg-helloであれば、まず「x-」を除去して「wg-hello」とし、そのあと、camelCase形式「wgHello」とします。directiveメソッドの引数nameで指定しているのは正規化された名前なので、この例であれば、実際には「wg-hello」「x_wg_hello」「data-wg-hello」などの形式で呼び出せます。

 引数factory(ファクトリー関数)は、ディレクティブを定義するためのオブジェクトを戻り値として返す必要があります(2)。ディレクティブオブジェクトには、以下のようなプロパティを指定できます。

プロパティ 概要
template ディレクティブに適用するテンプレート(文字列)
templateUrl ディレクティブに適用するテンプレート(指定のファイル)
restrict ディレクティブの適用先(E:要素、A:属性など。詳細後述)
trunsclude 配下のコンテンツをテンプレートに反映するか
multiElement 複数の要素にまたがったディレクティブであるか
scope ディレクティブに適用するスコープ
require ディレクティブ同士の依存関係
priority ディレクティブ実行の優先順位(数値が大きいものほど優先順位も高い)
ディレクティブオブジェクトの主なプロパティ

 全てのプロパティは任意なので、適宜、必要に応じて組み合わせを使い分けます。この例であれば、templateプロパティを利用して、wg-helloディレクティブの配下に「<p>こんにちは、世界</p>」という文字列(テンプレート)を埋め込んでいます(3)。

 restrictは、ディレクティブを適用する箇所を指定するためのプロパティです(4)。設定可能な値には、以下のようなものがあります。

設定値 利用例
E(要素)
A(属性)
C(クラス)
M(コメント)
restrictプロパティの設定値

 ただし、一般的には、E(要素)、A(属性)以外を利用することはほとんどありませんし、利用すべきではありません。デフォルトは「EA」(要素か属性)なので、上記のサンプルコードでは要素としてだけ呼び出せるよう、「E」としています。

 このように定義されたwg-helloディレクティブは、標準ディレクティブと同じ要領で呼び出せることも確認しておきましょう(5)。開発者ツールから確認してみると、以下のようにディレクティブの配下にテンプレートが反映されていることも確認できます。

HTML
<wg-hello>
  <p style="background-color:Yellow">こんにちは、世界!</p>
</wg-hello>
ディレクティブが適用された結果(開発者ツールで確認したHTMLソース)
処理対象:ディレクティブ カテゴリ:基本
処理対象:自作 カテゴリ:ディレクティブ
API:angular.Module カテゴリ:ng(コアモジュール) > type(型)

※以下では、本稿の前後を合わせて5回分(第70回~第74回)のみ表示しています。
 連載の全タイトルを参照するには、[この記事の連載 INDEX]を参照してください。

AngularJS TIPS
70. AngularJSのサービスを単体テストするには?

テスティングフレームワーク「Karma+Jasmin」を使って、AngularJSの「サービス」の単体テストを記述し、それを実行する方法を解説する。

AngularJS TIPS
71. AngularJSのコントローラーを単体テストするには?

テスティングフレームワーク「Karma+Jasmin」を使って、AngularJSの「コントローラー」の単体テストを記述し、それを実行する方法を解説する。

AngularJS TIPS
72. 【現在、表示中】≫ ディレクティブを自作するには?(directiveメソッド)

AngularJSで、ビューの操作/生成を独立させて独自ディレクティブを作成する基本的な定義方法と使用例を説明する。

AngularJS TIPS
73. ディレクティブで利用するテンプレートを外部ファイル化するには?(templateUrlプロパティ)

ビューの操作/生成を定義した自作ディレクティブのテンプレートを外部ファイル化して利用する方法を解説。また、ビューの中で<script>要素としてテンプレートを宣言する方法も説明する。

AngularJS TIPS
74. ディレクティブ配下のコンテンツをテンプレートに反映させるには?(transcludeプロパティ)

自作ディレクティブ呼び出し側で指定した「配下のコンテンツ」をテンプレートに反映させることで、そのディレクティブ要素の下に埋め込まれるHTMLコードを動的に切り替える方法を説明する。

サイトからのお知らせ

Twitterでつぶやこう!