JavaScript
AngularJS

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

More than 3 years have passed since last update.

AngularJS v2.0 Design Docs の中で、directive 周りについて書かれている Templating の内容をざっと読んでまとめてみました。Controller がなくなる 2.0 では最も気になる部分です。

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

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

まだの方は、まず ng-europe のビデオ を見ることをおすすめします。


まとめ

最初にまとめを。


  • 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> を使う。

<ul>

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

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

<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 という Design Doc が前者の記法についてのもののようです。まだ書き途中の模様。

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


Directive API


アノテーション

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



  • selector: どの DOM 要素に適用するかの CSS セレクタ。input[type="text"], [ng-show] とか。


  • events: directive で使うイベント一覧。テンプレートで on-xxx="" と使えるように。


  • visibility: どの directive インスタンスからアクセス可能にするか。同じ要素、直接の子供、子孫全部から選べる。


  • microsyntax: ng-repeat のような特殊な記法を使いたい際に利用。

@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 できる。

@ComponentDirective

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

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

@ComponentDirective

class ChildComponent() {
constructor(element: HTMLElement, parent: ParentComponent) {
}
}


データバインディング

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

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


フック

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


  • attach

  • detach

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


イベント

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

@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 サポートしてないブラウザでも動くようにはする模様。