(Angular 2 の alpha.13 に基づいた内容です。)
昨日 ng-japan に参加した際に Angular 2 に触ってみたのですが、If
とか Foreach
の書き方が謎だったので調べてみました。
ちなみに Viewport Directive というのは、以前 Template Directive と呼ばれていた Angular 2 の 3 種類の Directive のうちの一つで、HTML に新しい DOM を挿入するものです。If
, Foreach
はこれに当たります。
書き方のバリエーション
If
は、以下のどれでもいいそうです。
<template [if]="foo">
<p>Show me!</p>
</template>
<p template="if: foo">Show me!</p>
<p *if="foo">Show me!</p>
Foreach
も、以下のどれでもいいそうです。
<template foreach #foo [in]="foos">
<li>{{foo.text}}</li>
</template>
<li template="foreach #foo in foos">{{foo.text}}</li>
<li *foreach="#foo in foos">{{foo.text}}</li>
え、なにそれ、どういうこと?
<template></template>
への正規化と microsyntax
If, Foreach などの実装は https://github.com/angular/angular/tree/2.0.0-alpha.13/modules/angular2/src/directives にあるので読んでみました。
If は if
という属性があるかとその値しか見ていないし、Foreach も(概ね) foreach
と in
という属性があるかと in
の値しか見てません。ということは、Directive がテンプレートの処理を開始する前に、一番上の <template></template>
の形式に正規化されているということです。
ViewSplitter なるもので、以下の変換をしているようです。
-
*
から始まる属性値を template 属性に。例えば*foreach="#foo in foos"
->template="foreach #foo in foos"
-
template=""
の属性値(microsyntax)をパースし、<template></template>
を作ってその属性を設定。例えばtemplate="foreach #foo in foos"
-><template foreach #foo [in]="foos"></template>
なので、上の例だと下のものから順に上に変換されているイメージです。
2 の microsyntax のパースの部分は、ドキュメントだけ読むとよく意味がわかりませんが、コードやテストを読んだところ、結局一定のルールに従って <template></template>
に設定するための複数の属性を取り出すよ、ということのようです。
Viewport Directive の仕組み
<template></template>
の書き方の面白いところは、ただの属性なので順番はどうでもいいという点です。以下のどれでもいいわけですね。
<template foreach #foo [in]="foos"></template>
<template foreach #foo [in]="foos"></template>
<template #foo foreach [in]="foos"></template>
<template #foo [in]="foos" foreach></template>
<template [in]="foos" foreach #foo></template>
<template [in]="foos" #foo foreach></template>
ちなみに #foo
は implicit variable というらしく、Directive の方では \$implicit
という名前の local を設定すればそこに値を渡せる模様。
結論
他人の書いた Viewport Directive を使うときは安心して *foreach=""
のような形式が使えます。要素が複数の時は <template></template>
で囲む必要がありますが。
自分で Viewport Directive を作るときは、例の microsyntax でいい感じに書けるように、使う属性をうまく決める、という感じでしょうか。
とりあえずすっきり。