[AngularJS] 8. カスタムディレクティブ

---
[目次](http://qiita.com/Koizumi-Greenwich/items/3e327e3331b2f728797e)
≪前の記事 7.[ディレクティブ](http://qiita.com/Koizumi-Greenwich/items/287d36dfeb70333e00a4)
≫次の記事 9.[ルートスコープ](http://qiita.com/Koizumi-Greenwich/items/aa3ac1aafbf1ec2a0c62)

---
#カスタムディレクティブ
カスタムフィルタと同様に、独自のディレクティブ＝カスタムディレクティブを定義することができます。すなわち、独自のHTML要素（タグ）や属性、あるいは特定の振る舞いをする特殊なクラス値を定義することができるということです。


#ディレクティブの定義
ディレクティブの定義は、Angularモジュールの **directive**メソッドで行います。

```text:ディレクティブ定義の書式
モジュール.directive(ディレクティブ名, function() {
    return {
        〜ディレクティブ定義パラメータ〜
    };
});
```

directiveメソッドの第1引数は、 **ディレクティブ名**です。 **キャメルケース**で指定してください。
第2引数はディレクティブのオブジェクトを生成する **ファクトリー関数**です。
ファクトリー関数では **ディレクティブ定義のパラメータ**を、ハッシュオブジェクトで返すようにします。

##ディレクティブ定義パラメータ
ディレクティブ定義には数多くのパラメータが用意されています。ここではよく使われる主なパラメータを紹介します。（詳細は[ここを参照](http://js.studio-kingdom.com/angularjs/ng_service/$compile)）

###restrict
restrictパラメータは、ディレクティブの形式（宣言スタイル）の指定です。E、A、C、Mのいずれか、または複数を指定することで、そのディレクティブがHTML要素なのか、属性なのか、クラス値なのかを決定します。
restrictパラメータを省略した場合、デフォルトは **A**、すなわち属性になります。

- E ... HTML要素 Ex. `<my-directive>...</my-directive>`
- A ... 属性 Ex. `<div my-directive="...">...</div>` ※デフォルト
- C ... クラス値 Ex. `<div class="my-directive">...</div>`
- M ... コメント Ex. `<!-- directive: my-directive -->`

```js:restrictの例
module.directive('myDirective' function() {
    return {
        restrict: 'EA',
    };
});
```

上記の例では、`myDirective`をHTML要素または属性として使用することが出来ます。

###template
templateパラメータは、現在の要素（ディレクティブ自身、またはディレクティブが指定されたHTML要素）の内容を、指定されたテンプレート文字列と置き換えます。
テンプレートの断片を部品化して管理したい場合などに便利な機能です。

```js:tempalteの例
module.directive('myDirective' function() {
    return {
        template: "{{year}}年{{month}}月{{day}日",
    };
});
```

上記のディレクティブを使用したテンプレートの例です。

```html:templateディレクティブの使用例
<div my-directive></div>
```

このテンプレートのmyDirectiveが処理されると、次のように展開されます。

```html:templateディレクティブの展開例
<div my-directive>{{year}}年{{month}}月{{day}日</div>
```

myDirectiveのtemplateパラメータの内容が、指定された要素の内容として置換、展開されます。

###templateurl
templateパラメータと同様の動作ですが、文字列では無く、テンプレートファイルのURLで指定します。

```html:date.html
{{year}}年{{month}}月{{day}日
```

上記のテンプレートを templateurlパラメータで指定した例です。

```js:tempalteの例
module.directive('myDirective' function() {
    return {
        templateurl: "date.html",
    };
});
```

###replace
template、templateurlで指定したテンプレートの置換の挙動を決めます。

- trueの場合、テンプレートを、現在の要素と置き換えます。
- falseの場合、テンプレートを、現在の要素の内容と置き換えます。

デフォルトは false です。

###controller
ディレクティブ内の範囲のみで動作するコントローラを定義することができます。
つまり、template|templateurlとcontrollerを併用することで、コントローラを含めた部品としてディレクティブを利用することができるのです。

###link
現在の要素（ディレクティブ自身、またはディレクティブが指定されたHTML要素）のDOMオブジェクトの操作やイベント処理、$scopeのプロパティ値を利用した処理を行う関数を定義できるパラメータです。

```text:linkパラメータ書式
link: function(scope, element, attrs) {
    〜DOM操作、scope値の処理〜
}
```

link関数の第1引数には、$scopeオブジェクトがセットされ、関数内で$scopeの値を利用、操作することができます。
第2引数には、現在の要素のDOMオブジェクトが渡されてきます。このオブジェクトを使って要素の操作やイベント処理を定義することが出来ます。
第3引数には、現在の要素に指定された属性とその値がハッシュオブジェクトで渡されてきます。link関数にパラメータを渡したい場合などに利用します。

以下は、jQueryプラグイン [DateTimePicker](http://xdsoft.net/jqplugins/datetimepicker/) を利用した inputフィールドを記述する例です。

```html:input.html
<input ng-model="datetime" date-time-picker>
```

```js:dateTimePickerディレクティブ
module.directive('dateTimePicker' function() {
    return {
        link: function(scope, element, attrs) {
            $(element).datetimepicker({format:'Y-m-d H:i:s'});
        }
    };
});
```

この例では、link関数に渡されてきた要素オブジェクトを使ってDateTimePickerを実装させています。

#サンプルコード
```html:sample08-date.html
{{year}}年{{month}}月{{day}}日 {{hour}}時{{min}}分
```

```html:sample08.html
<!DOCTYPE html>
<meta charset="UTF-8">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jquery-datetimepicker/2.4.5/jquery.datetimepicker.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-datetimepicker/2.4.5/jquery.datetimepicker.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
<script>
/**
 * アプリケーション モジュール オブジェクトの定義
 */
SampleModule = (function() {
    var module = angular.module("sampleModule", []);
    
    /**
     * dateTimePickerディレクティブ
     */
    module.directive('dateTimePicker', function(){
        return {
            link: function(scope, elem, attrs) {
                $(elem).datetimepicker({format:'Y-m-d H:i:s'});
            }
        };
    });
    
    /**
     * dateTemplateディレクティブ
     */
    module.directive('dateTemplate', function(){
        return {
            template: "{{year}}年{{month}}月{{day}}日",
        }
    });
    
    /**
     * dateTemplateUrlディレクティブ
     */
    module.directive('dateTemplateUrl', function(){
        return {
            restrict: 'E',
            templateUrl: "sample08-date.html",
        }
    });
    
    return module;
})();

/**
 * コントローラの定義
 */
(function(module) {
    /**
     * SampleController
     */
    module.controller("sampleController", function($scope, $timeout){
        // 日時が入力されたら年月日時分を分解する
        $scope.$watch('datetime', function(){
            if ($scope.datetime) {
                $scope.year  = $scope.datetime.substr(0, 4);
                $scope.month = $scope.datetime.substr(5, 2);
                $scope.day   = $scope.datetime.substr(8, 2);
                $scope.hour  = $scope.datetime.substr(11, 2);
                $scope.min   = $scope.datetime.substr(14, 2);
            }
        });
    });
})(SampleModule);
</script>

<!-- sampleModule テンプレート -->
<div ng-app="sampleModule">
    <!-- sampleController テンプレート -->
    <div ng-controller="sampleController" ng-cloak>
        <p>入力した日時をtemplate/templateUrlディレクティブで表示する</p>
        <h2>dateTimePickerディレクティブ</h2>
        <p>日時：<input ng-model="datetime" date-time-picker="hogehoge"></p>
        <h2>dateTemplateディレクティブ</h2>
        <p date-template></p>
        <h2>dateTemplateUrlディレクティブ</h2>
        <date-template-url></date-template-url>
    </div>
</div>
```
---
[目次](http://qiita.com/Koizumi-Greenwich/items/3e327e3331b2f728797e)
≪前の記事 7.[ディレクティブ](http://qiita.com/Koizumi-Greenwich/items/287d36dfeb70333e00a4)
≫次の記事 9.[ルートスコープ](http://qiita.com/Koizumi-Greenwich/items/aa3ac1aafbf1ec2a0c62)

---