前回の続きです。
今回はDirective
(ディレクティブ)についてです。
ngModel
やngRepeat
などを既に使っているのでディレクティブがどんなものかは大体分かっているかと思います。
ビルドインのディレクティブ一覧 => http://docs.angularjs.org/api/ng#directive
####なので早速ですがディレクティブを作ります。
単純なディレクティブ
レイアウトを持たず、動作を追加するディレクティブを作ってみます。
ちょうどTwitter Bootstrapが雛形に使われているので、リンクにツールチップを追加します。
<!-- app/views/main.html -->
<p>
<input type="text" ng-model="world">
<span ng-click="addFramework(world)" class="btn btn-primary">Add</span>
</p>
<p>Hello {{ world }}!</p>
<div>
<h3>{{ frameworks.length }} frameworks</h3>
<input type="text" ng-model="searchText" />
<span ng-hide="frameworks">読み込み中...</span>
<ul>
<li ng-repeat="f in frameworks | reverse | filter:searchText">
<!—- tooltip属性を追加する -—>
<a ng-href="/#/frameworks/{{f}}" tooltip>{{f|uppercase}}</a>
</li>
</ul>
</div>
tooltip
ディレクティブを定義します。
// app/scripts/app.js
/* jshint indent: 4, unused: false */
'use strict';
angular.module('angularSampleApp', [
'ngCookies', 'ngResource', 'ngSanitize', 'ngRoute'
])
.factory(‘…’, function () {})
// tooltip ディレクティブを定義
.directive('tooltip', function () {
return function (scope, element, attr) {
element.tooltip({
title: 'tooltip test'
});
};
});
省略型はクロージャを返却して定義とします。
この場合はtooltip
ディレクティブが設定されているDOMに対して、ツールチップを表示するだけです。
scope
element
attr
は インジェクターからインジェクトされた物ではないです。
element
はただのjQueryオブジェクトなので、DOM操作はなんでもできますね!
ディレクティブにパラメータを渡す
先ほど作ったディレクティブを少し弄ります。
<!-- app/views/main.html -->
<p>
<input type="text" ng-model="world">
<span ng-click="addFramework(world)" class="btn btn-primary">Add</span>
</p>
<p>Hello {{ world }}!</p>
<div>
<h3>{{ frameworks.length }} frameworks</h3>
<input type="text" ng-model="searchText" />
<span ng-hide="frameworks">読み込み中...</span>
<ul>
<li ng-repeat="f in frameworks | reverse | filter:searchText">
<!—- ディレクティブに変数を渡す -—>
<a ng-href="/#/frameworks/{{f}}" tooltip="f">{{f|uppercase}}</a>
</li>
</ul>
</div>
tooltip
ディレクティブに変数f
を渡す。
// app/scripts/app.js
.directive('tooltip', function ($parse) { // expressionを評価するためのサービス
// オプションを指定する場合はオブジェクトを返す
return {
restrict: ‘A’,
link: function (scope, element, attr) {
// attr.tooltip=“f” を指定したので、fの中身を取得し、ツールチップに設定
// scope.$eval(attr.tooltip) でもよい
var value = $parse(attr.tooltip)(scope);
element.tooltip({
title: value
});
}
};
});
attr.tooltip
の中身はただの文字なので、評価した結果をツールチップに渡します。
値の変更を監視してjsを実行したい場合は、scope.$watch()
を使えばよいです。
http://docs.angularjs.org/api/ng.$rootScope.Scope#methods_$watch
restrict?
ディレクティブのrestrict
はディレクティブの対象を制限する為に使います。
- E <some-directive></some-directive>
- A <div some-directive=“”></div>
- C <div class=“some-directive”></div>
- M <!-— directive: some-directive -—>
複数指定する場合は restrict: ‘AEC’
の様に繋げて書きます。
テンプレート
ディレクティブにはテンプレートの機能があります。
// app/scripts/app.js
.directive('tooltip', function ($parse) {
return {
restrict: 'A',
// テンプレートを追加
template: '<span class="glyphicon glyphicon-asterisk"></span>',
link: function (scope, element, attr) {
var value = $parse(attr.tooltip)(scope);
element.tooltip({
title: value
});
}
};
});
一応これだけでテンプレートが反映されますが、固定文ではダメなのでngTransclude
を使います。
ngTransclude
// app/scripts/app.js
.directive('tooltip', function ($parse) {
return {
restrict: 'A',
// テンプレートを編集
template: '<span class="glyphicon glyphicon-asterisk"></span> <i ng-transclude></i>',
// transcludeを設定
transclude: true,
link: function (scope, element, attr) {
var value = $parse(attr.tooltip)(scope);
element.tooltip({
title: value
});
}
};
});
テンプレートのどこに内容をセットするかをngTransclude
で指定するだけなので簡単です。
ディレクティブ間の連携
公式ドキュメント(http://docs.angularjs.org/guide/directive#creating-custom-directives_demo_creating-directives-that-communicate)にいい感じの説明があるので、今回は省略します。