Angular 2.0 のディレクティブ周りはこうなる？


[AngularJS v2.0 Design Docs](https://drive.google.com/drive/#folders/0BxgtL8yFJbacQmpCc1NMV3d5dnM/0BxgtL8yFJbacUnUxc3l5aTZrbVk/0B7Ovm8bUYiUDR29iSkEyMk5pVUk) の中で、directive 周りについて書かれている [Templating](https://docs.google.com/document/d/1f5VWROeTI2kJwVKbNsrHuEz5IqtZe14OpoxM9fEYJNU) の内容をざっと読んでまとめてみました。Controller がなくなる 2.0 では最も気になる部分です。

2014/11/3 当時の内容であり、どんどん変わっていくと思われます。かなり内容をはしょってあるので悪しからず。

また ng-europe での発表と食い違ってるところもあり、どっちが新しいのか不明です。あくまでも、雰囲気を掴む程度に・・・。

まだの方は、まず [ng-europe のビデオ](https://www.youtube.com/watch?v=gNmWybAyBHI) を見ることをおすすめします。

## まとめ

最初にまとめを。

- 1.x の自由で複雑すぎた directive を、3 つのパターンに分類。
- @ アノテーションでいろいろ設定。
- DI で他のディレクティブと通信できる。
- Web Components 的な方向に。まだしっかり詰まってなさそう。

1.x で controller, directive を書くときも、3 つのパターンを意識して書くと良さそうです。

## 概要

1.x の directive は複雑すぎた。2.0 では部品を減らし単純化する。

Angular ではカスタム要素を作るのではなく、DOM 要素に振る舞いを結びつける。この振る舞いが directive。JavaScript class で、マッチする要素ごとにインスタンス化される。

DOM 要素同様、directive もプロパティ（属性ではないのに注意。JavaScript で触れるやつ。）とイベントを使って作られる。

## Directive の種類

1.x の経験により必要なパターンは以下の三つ。

- Decorative Directive
- Template Directive
- Component Directive

### Decorator Directive

要素に機能を追加する。ツールチップをつけたり、要素の表示非表示を制御したり。`ng-show` など。

### Template Directive

DOM 要素をテンプレートにしてしまうもの。DOM 要素があった場所は、テンプレートのインスタンスが置ける hole（要素を置ける場所、のような意味？）になる。

`ng-if`, `ng-repeat`, `ng-view`, `ng-switch`, `ng-include` など。

Execution context を作っても良い。`ng-repeat` など。`ng-if` などでは親 component の context をそのまま使えば良いので必要なし。

基本的なケースでは `<template></template>` を使う。

```html
<ul>
  <template ng-repeat>
    <li>...</li>
  </template>
</ul>
```

直下の要素が一個の場合は以下でも良い。

```html
<ul>
  <li ng-repeat>...</li>
</ul>
```

`<template></template>` で囲むことで、1.x にあった `ng-repeat-start`, `ng-repeat-end` のような directive は不要になる。

### Component Directive

JavaScript のロジック、HTML テンプレート、（必須ではないけど）CSS をまとめたもの。

Execution context はアプリケーションの他の部分から独立している。テンプレート中でアクセスできるプロパティとメソッドは、対応する component directive のものだけ。

Shadow DOM を使うらしい。

Component のインターフェイスは以下。

- プロパティとイベント
- CSS プロパティ: Shadow DOM 的な方法で指定できる。
- 子要素: テンプレートで子 component の中に要素を入れることができる。それらの要素の execution context は子 component ではなく親 component のもの。（親のテンプレートに書くので普通に考えたらそうなる。）

## Expressions

属性の値は全て expression。1.x では、ものによって違った.

ng-europe で発表されていたのは `(click)="doSomething"`, `[checked]="isSelected"` みたいなのだったけど、Design Doc では `on-xxx=""`, `bind-xxx=""` と書いてある。前者が新しい？

追記: [Angular v2 Template Syntax Summary](https://docs.google.com/document/d/1hymWCAhCYDWH2yHVmS4_Ep2puPyYoFVHtX01MHEA7M8) という Design Doc が前者の記法についてのもののようです。まだ書き途中の模様。

1.x では `a.b.c` で `a` や `b` が `undefined` でもエラーにならなかったが、2.0 ではエラーになる模様。

## Directive API

### アノテーション

@ アノテーションで ES6 class にメタ情報を付加。以下は directive の種類によらず共通な属性。

- `selector`: どの DOM 要素に適用するかの CSS セレクタ。`input[type="text"]`, `[ng-show]` とか。
- `events`: directive で使うイベント一覧。テンプレートで `on-xxx=""` と使えるように。
- `visibility`: どの `directive` インスタンスからアクセス可能にするか。同じ要素、直接の子供、子孫全部から選べる。
- `microsyntax`: `ng-repeat` のような特殊な記法を使いたい際に利用。

```javascript
@TemplateDirective(
  selector: '[ng-repeat]',
  microsyntax: {
    'ng-repeat': '$item-name in	$collection [track by $track-by]'
  }
)
class NgRepeat {
  // ...
}
```

### DI

コンストラクタに DI。Http など UI に関係ないものの他に、DOM 要素（HTMLElement）や他の directive を inject できる。

```javascript 
@ComponentDirective
class ChildComponent() {
  @Inject(HTMLElement, ParentComponent)
  constructor(element, parent) {
  }
}
```

おそらく型アノテーションでもできるはず？

```javascript
@ComponentDirective
class ChildComponent() {
  constructor(element: HTMLElement, parent: ParentComponent) {
  }
}
```

### データバインディング

Directive の全てのプロパティはデータバインディングに利用可能。

`@PropertySet` を使うと、setter の実行条件を細かく指定できる。参照が変わったか、コレクションの中身が変わったか、など。



### フック

ライフサイクルフックもある。Directive クラスにあらかじめ決まった名前のメソッドを定義する。

- `attach`
- `detach`

TemplateDirective だけ `templateLoaded` というのがある。

### イベント

カスタムイベントを投げられる。Component に到達するまで DOM tree を登っていく。

```javascript
@ng.DecoratorDirective(
  selector: 'dialog',
  events: ['close']
)
class Dialog {
  @Inject(window.HTMLElement)
  constructor(element) { ... }
  close() {
    var evt = new Event('close');
    this.element.dispatchEvent(evt);
    if (!evt.defaultPrevented()) {
      // Really close the dialog...
    }
  }
}
```

多分 component の template で `on-close="componentMethod()"` みたいな感じで使われるはず。

## Web Components

Custom Elements API が利用可能な場合、component たちは、custom element として登録される。それで Polymer や X-Tag から使えるようになるとか。

Polymer とどう折り合いをつけるかは未定のよう。

Shadow DOM サポートしてないブラウザでも動くようにはする模様。