吉本集の個人ブログ
Web制作の技術について書いています。たまに日記も書きます。

directiveメソッド、link関数とcompile関数の違い(基本)

2013年12月9日 / category : angularjs, directive, lab

directiveメソッドの属性には、2種類の関数があります。
link関数とcompile関数です。
現在この2種類の関数について、勉強中ですが、私のほうで理解したところまでを紹介します。
両方とも、directiveメソッドが実行されたタイミングで実行されます。
基本的な記述方法は、下記の通り

link
myApp.directive('myLink', function(){
	return {
		link: function(_scope, _element, _attars){
			//処理
		}
	};
});
compile
myApp.directive('myCompile', function(){
	return {
		compile: function(_element, _attars){
			//処理
		}
	};
});

ただ、この2種類の関数を同時に記述することはできません。

link & compile
myApp.directive('myCompile', function(){
	return {
		compile: function(_element, _attars){
			//処理される。
		},
		link: function(_scope, _element, _attars){
			//処理されない。
		}
	};
});

上記のように2種類の関数を同時に記述すると、link関数は実行されません。
return内の処理の順番は、下記のようなイメージとなります。

1.HTML文字列をDOMに変換する。
2.compile関数の実行
3.link関数の実行

2種類の関数を同時に記述することはできないが、compile関数の実行の後、link関数を実行したい場合は下記のような記述になります。

compile → link
myApp.directive('myCompile', function(){
	return {
		compile: function(_element, _attars){
        		//処理される。
			return function(_scope, _element, _attars){
				//処理される。
			}
		}
	};
});

compile関数内のreturnの関数が、link関数となります。
また、特徴として、compile関数の引数には、scopeがありません。

具体的にどんなことができるかサンプルを見てみましょう。

■サンプルURL
http://tsudoi.org/javascript/angularjs/Reference/Blog/11/link_compile/
■サンプルファイル一式
ダウンロード – zip

サンプルの上2つ「link」「compile」と文字が配置されているエリアですが、青いボックスがフェードインしてくると思います。
動きは同じですが、仕組みはlink関数、compile関数と使い分けています。
該当する箇所だけ、下記に書き出します。

■HTML – index.html
<div class="wrap" ng-controller="CtrlLink">
<p>link</p>
<div my-link></div>
</div>

<div class="wrap" ng-controller="CtrlCompile">
<p>compile</p>
<div my-compile></div>
</div>
■CSS – styles.css
.red{
	background:#f00;
}

.blue{
	background:#00f;
}
■JavaScript – app.js
myApp.controller('CtrlLink', ['$scope', function($scope){
	$scope.value = 'red';
}]);

myApp.controller('CtrlCompile', ['$scope', function($scope){
	$scope.value = 'red';
}]);

myApp.directive('myLink', function(){
	return {
		template: '<div class="{{value}}"></div>',
		link: function(_scope, _element, _attars){
			$(_element).hide().fadeIn(2500);
			_scope.value = 'blue';
		}
	};
});

myApp.directive('myCompile', function(){
	return {
		template: '<div class="{{value}}"></div>',
		compile: function(_element, _attars){
        		$(_element).hide().fadeIn(2500);
			return function(_scope, _element, _attars){
				_scope.value = 'blue';
			}
		}
	};
});
■解説
両方とも、controllerメソッドでボックスのクラス名に「red」を代入し、赤色にしていますが、directiveメソッドのlink関数、compile関数で、クラス名を「blue」に変更しています。その後、フェードインさせているので、青いボックスが表示されます。
また、compile関数には、scopeを取得する引数がないため、returnを使用し、link関数を使用する必要が出てきます。

次に、サンプルの下2「link – loop」「compile – loop」についてですが、「link – loop」は10個のボックスがランダムに色が変更されています。「compile – loop」は10個とも色が同じになっているはずです。
これは、どういうことかと言うと、ng-repeat属性で要素をリピートした場合、link関数は、そのループ分、関数が実行されますが、compile関数は、1回だけしか実行されないのです。
該当のコード部分だけ、下記に書き出します。

■JavaScript – app.js
myApp.directive('myLinkLoop', function(){
	var _colors = ['red','green','blue'];
	return {
		template: '<div class="{{value}}"></div>',
		link: function(_scope, _element, _attars){

        		//ループ分、実行される
			$(_element).hide().fadeIn(2500);
			_scope.value = _colors[ Math.floor( Math.random() * _colors.length ) ];

		}
	};
});

myApp.directive('myCompileLoop', function(){
	var _colors = ['red','green','blue'];
	return {
		template: '<div class="{{value}}"></div>',
		compile: function(_element, _attars){

        		//1度しか実行されない
			var _color = _colors[ Math.floor( Math.random() * _colors.length ) ];

			return function(_scope, _element, _attars){ //link関数

            			//ループ分、実行される
				$(_element).hide().fadeIn(2500);
				_scope.value = _color;

			}
		}
	};
});