親コントローラと連携したカスタムディレクティブを作成する
続いて、先ほど作成した例を元に、親となるコントローラと連携したディレクティブを作成します。前回の例では、テンプレートのhello属性に値を指定していないので静的なコンテンツと変わりがありませんでしたが、今回は属性を利用し、また、コントローラ内で変更する$scope変数の値に応じた表示を行うディレクティブを作成します。
今回のサンプルは、図2のようにテンプレートで指定したhello属性の値を取得する方法と、HelloControllerで定義した$scope.message変数の値をディレクティブで取得する方法の例を示します。$scope.message変数の値は、時間経過とともに変化するものとします。
テンプレートは前回利用したサンプルを元にリスト3のように変更します。
<!DOCTYPE html>
<html lang="ja" ng-app="hello">
<head >
<script type="text/javascript" src="../vendors/jquery-2.1.4.min.js"></script> <!-- (1)jQueryの利用 -->
<script type="text/javascript" src="../vendors/angular.js"></script>
<script type="text/javascript" src="hello.js"></script>
</head>
<body ng-controller="HelloController"> <!-- (2)HelloControllerを利用する -->
<div hello="en"></div> <!-- (3)属性値を利用する -->
<div hello="ja"></div>
</body>
</html>
今回はjQueryを使ってDOMを操作しますので、(1)のようにjQueryを読み込みます[*]。また、連携するコントローラであるHelloControllerを(2)のように指定します。
続いて、今回作成するhelloディレクティブを(3)のように記述します。指定する属性値によって表示を切り替えるために、異なる2つの値をここでは指定しておきます。
また、実際のhelloディレクティブの実装例を示したものがリスト4です。
注
[*] サンプルに示したレベルであればjqLiteで十分なので、必ずしもjQueryを使う必要はありません。ただし、アプリにjQueryのプラグインを組み込むこともよくあるので、今回はその例として、DOM操作にjQueryを用いています。
(function(){
'use strict';
angular.module('hello',[])
.controller('HelloController',['$timeout','$scope',HelloController]) // (1)HelloControllerの利用
.directive('hello',[HelloDirective]);
function HelloController($timeout,$scope){
// (2)意図的に遅延したmessageオブジェクトを作成する
$timeout(function(){
$scope.message = {
ja : 'こんにちは',
en : 'Hello'
};
},1000);
// (3)messageオブジェクトの内容を変更する
$timeout(function(){
$scope.message = {
ja : 'さようなら',
en : 'Bye Bye'
};
},5000);
}
function HelloDirective(){
return function($scope,element,attrs){
// (4)<div hello="ja"></div>でのhello属性を取得する
var lang = attrs['hello'];
// (5)コントローラ内の $scope.message[lang] の変数の変化によりDOMを操作する
$scope.$watch('message.' + lang,function(newVal){
if(newVal){
$(element).empty().append(newVal).show();
}
else{
$(element).hide();
}
});
}
}
}());
(1)では、連携するコントローラであるHelloControllerを定義します。続いて表示の際に利用する$scope.messageオブジェクトを(2)のように作成します。
実際の値はAjaxなどで非同期に取得することなどを想定して、$timeoutサービス使って値を遅らせて作成しています。同様に(3)でもさらに遅らせて$scope.messageの値を更新します。
続いて、helloディレクティブの本体を実装していきます。
(4)では、テンプレートで指定されたhello属性の値を取得しています。例では"en"もしくは"ja"という値が取得でき、表示するための変数として$scope.message.enもしくは$scope.message.jaという変数を利用します。そのため表示する変数値として利用したいところですが、実際には最初の実行時には、変数自体が未定義であり、その後、1秒後、5秒後と変数の値が変わっていきます。
従って、その値の変化時に値を変えなければいけませんので、その変化を追跡する必要があります。
そのための方法として$scope.$watchメソッドがあります。$scope.$watchメソッドでは、監視すべきスコープ内の変数と、コールバック関数を指定することで、$scope変数の変化に応じた処理を実装できます。
ここでは、(5)のように$scope.$watchメソッドを使って変数の値が変更された時に、DOM操作をするようにします。このようなにコントローラなどと連携することで、先ほどのHello Worldのサンプルと同じ知識で多少複雑なことができるようになります。
