AngularJSのディレクティブについて
明日AngularJSのハッカソン(AngularJS ハッカソン - AngularJS Japan User Group | Doorkeeper)に参加することになったので、AngularJSを一から勉強してみることにした。そこで今回は、AngularJSのディレクティブについて解説していきたい。
1. AngularJSのディレクティブとは
AngularJSのディレクティブとは、双方向バインドを実現するための仕組みである。
AngularJSで言うところの双方向バインドでは、具体的に以下の2つの処理が行われる。
1.Model(=scope)の変更をView(=DOM)へ反映する
2.Viewの変更時にscopeの値を変更する
具体的に、双方向バインドは、AngularJSのHTMLコンパイラが、DOM要素(クラス、属性、HTMLタグ、コメント等)からディレクティブを検出し、そこに対応するスクリプトを埋め込むことで実現される。
AngularJSには標準で組み込まれているディレクティブが多数ある。
例えば、テキストボックスの入力値とscope.nameを紐付ける場合、htmlに下記を記述するだけで、ユーザの入力値がscopeへ即時反映される。
<input type="text" ng-model="name" /> <span>{{name}}</span>
他にも、ngBind、 ngRepeat や ngClassなどのディレクティブがある。詳しくは、こちらの標準ディレクティブ一覧を参照して頂きたい。(https://docs.angularjs.org/api/ng/directive)
2. カスタムディレクティブ
実装したい機能が標準のディレクティブを使って出来ない場合は、自分で自由にディレクティブを作る事ができる。
これをカスタムディレクティブと言う。以下、作る際の注意点を二つ挙げる。
1.ディレクティブの定義には、angular.moduleのdirective関数を利用すること
2.ディレクティブをスクリプトファイルで定義する際はキャメルケースを用いるが、テンプレートで利用する時はハイフン繋ぎ(アンダースコア、コロンでも良い)にすること
以下、簡単なカスタムディレクティブを作ってみた。例としてあまり適切でないかもしれないが、下記を実行すれば、「初めてのディレクティブ」が表示されたはずだ。
//myModule.js var myModlue = angular.module('myModlue', []); myModule.directive('firstDirective', function(){ return { template: '<span>初めてのディレクティブ</span>' }; });
<!doctype html> <html ng-app="myModule"> <head> <script type="text/javascript" src="angular.min.js"></script> <script type="text/javascript" src="myModule.js"></script> </head> <body> <div first-directive></div> </body> </html>
3. ディレクティブのオプションでできることまとめ
カスタムディレクティブには、様々なオプションが用意されている。以下、それぞれのオプションでできることを一覧で示す。
なお、各オプションの詳しい解説は$compile | AngularJS 1.2 日本語リファレンス | js STUDIOを参照していただきたい。
1. ディレクティブ同士の優先順位を指定する
2. 新しいscopeをディレクティブ内で指定する
3. ひとつのディレクティブで複数のDOM要素を指定する
4. 指定するディレクティブよりpriorityの低いディレクティブの適用を外す
5. ディレクティブのscopeをcontrollerで使用可能にする
6. コントローラのコンストラクタ関数を定義する
7. 他のディレクティブで生成されたcontrollerを使う
8. ディレクティブがもつtemplate内で使えるディレクティブのcontrollerのエイリスを指定する
9. templateでのディレクティブの指定方法を定義する
10. ディレクティブがもつtemplateをhtml文字列として指定する
11. ディレクティブがもつtemplateをhtmlファイルのパスで指定する
12. templateでディレクティブを指定する際、子要素を挿入可能にする
13. scopeとtemplateを結びつける処理を指定する(compile)
14. scopeとtemplateを結びつける処理を指定する(link)
1. ディレクティブ同士の優先順位を指定する
priority: 10 //数字が大きければ大きいほど、優先度が高く先にコンパイルされる。
2. 新しいscopeをディレクティブ内で指定する
scope: true //true にすることで、新しいscopeが作成される scope: { //hashオブジェクトを渡すことで、親scopeを継承しない'隔離scope'が作成される myDirective: '=', // '='は、双方向バインディング onChange: '&', // '&'は、指定した値を親scopeのcontextで実行する title: '@' // '@'は、ローカル(このディレクティブの)scopeの値をDOMに追加する }
3. ひとつのディレクティブで複数のDOM要素を指定する
multiElement : true
4. 指定するディレクティブよりpriorityの低いディレクティブの適用を外す
terminal : true //priorityとともに使う。trueに設定した場合、そのディレクティブよりpriorityが小さいディレクティブは実行されない。
5. ディレクティブのscopeをcontrollerで使用可能にする
bindToController : true
”隔離scope"がディレクティブで作成されて、controllerAsが使われているとき、bindToController : trueにすると、その作成された"隔離scope"が、controllerAsで指定されたcontrollerがインスタンス化された時に使用可能になる。
6. コントローラのコンストラクタ関数を定義する
controller : function($scope) { var panes = $scope.panes = []; $scope.select = function(pane) { angular.forEach(panes, function(pane) { pane.selected = false; }); pane.selected = true; };
7. 他のディレクティブで生成されたcontrollerを使う
require : 'sample-directive' //ディレクティブ名を指定する
8. ディレクティブがもつtemplate内で使えるディレクティブのcontrollerのaliasを指定する
controllerAs : 'sample-controller'
9. templateでのディレクティブの指定方法を定義する
restrict : 'E' //E:タグ ex)<sample-directive> //他にも、 // A : 属性 ex) <div sample-directive> // C : クラス ex) <div class="sample-directive;"> // M : コメント ex) <!-- directive: sample-directive -->
10. ディレクティブがもつtemplateをhtml文字列として指定する
template : '<div red-on-hover>{{delete_str}}</div>'
11. ディレクティブがもつtemplateをhtmlファイルのパスで指定する
templateUrl : 'directive.html' //loadは非同期で行われる
12. templateでディレクティブを指定する際、子要素を挿入可能にする
transclude : true
13. scopeとtemplateを結びつける処理を指定する(compile)
compileと14のlinkオプションは同時に使うことが出来ない。詳しい使い方については、JavaScript - AngularJSのDirectiveを理解する. - Qiitaを参照頂きたい。
compile : function compile(tElement, tAttrs, transclude) { return { pre: function preLink(scope, iElement, iAttrs, controller) { ... }, post: function postLink(scope, iElement, iAttrs, controller) { ... } } }
14. scopeとtemplateを結びつける処理を指定する(link)
link : function link(scope, element, attrs) { var format, timeoutId; function updateTime() { element.text(dateFilter(new Date(), format)); } scope.$watch(attrs.myCurrentTime, function(value) { format = value; updateTime(); }); element.on('$destroy', function() { $interval.cancel(timeoutId); }); // start the UI update process; save the timeoutId for canceling timeoutId = $interval(function() { updateTime(); // update DOM }, 1000); }
参照URL
JavaScript - AngularJSのDirectiveを理解する. - Qiita
https://docs.angularjs.org/api/ng/service/$compile
https://docs.angularjs.org/guide/directive
JavaScript - AngularJSのdirectiveとは - Qiita
以上