今日はテンプレートを組み合わせて複雑なテンプレートを構築する方法を説明します。
まずJavaScriptのコードを見てみましょう。
var App = Ember.Application.create();
App.UserView = Ember.View.extend({
templateName: 'user',
lhs: 8,
firstName: "Albert",
lastName: "Hofmann",
infoView: Ember.View.extend({
templateName: 'info',
posts: 25, hobbies: "Riding bicycles",
subInfoView: Ember.View.extend({
templateName: 'subInfo',
country: 'Japan'
})
})
});
App.UserView.create().append();
ViewクラスがUserView -> infoView -> subInfoView と階層構造を作っています。
それぞれのViewクラスは、テンプレートを指定するためのテンプレート名をtemplateNameメンバで指定します。
create().append() メソッドチェインで、明示的に描画を行なっています。
次にテンプレートを見てみます。
<script type="text/x-handlebars" data-template-name="user">
{{firstName}} {{lastName}}
<br>
{{view infoView}}
</script>
<script type="text/x-handlebars" data-template-name="info">
<b>posts:</b> {{view.posts}}
<br>
<b>hobbies:</b> {{view.hobbies}}
<br>
{{view view.subInfoView}}
</script>
<script type="text/x-handlebars" data-template-name="subInfo">
<b>country:</b> {{view.country}}
</script>
それぞれのViewのためのテンプレートを1つずつ定義しています。
{{view}}ヘルパを使って、子供Viewを指定しています。
子供Viewのテンプレートでは、変数スコープは親Viewのままになります。子供Viewのインスタンスを参照するためには、view変数のメンバにアクセスします。(このあたり、直感に反する動きで、かなり理解に手こずりました。)
viewのコンテキストの扱いが最近変わったようです。
https://gist.github.com/2494968
このプログラムは以下のHTMLを出力します。(バインディングのためのマークは省略しています)
Albert Hofmann
<br>
<b>posts:</b> 25
<br>
<b>hobbies:</b> Riding bicycles
<br>
<b>country:</b> Japan
Viewの階層構造を表現するためでなく、テンプレート部品化のためにテンプレートを分けることもできます。
サンプルを見てみましょう。
var App = Ember.Application.create();
App.UserView = Ember.View.extend({
templateName: 'user',
lhs: 8,
firstName: "Albert",
lastName: "Hofmann",
posts: 25,
hobbies: "Riding bicycles",
country: 'Japan'
});
App.InfoView = Ember.View.extend({
templateName: 'info'
});
App.SubInfoView = Ember.View.extend({
templateName: 'subInfo',
});
App.UserView.create().append();
テンプレートを指定するためだけに、InfoView, SubInfoViewを定義しています。
続いてテンプレートのコードを見てみましょう。
<script type="text/x-handlebars" data-template-name="user">
{{firstName}} {{lastName}}
<br>
{{view App.InfoView}}
</script>
<script type="text/x-handlebars" data-template-name="info">
<b>posts:</b> {{posts}}
<br>
<b>hobbies:</b> {{hobbies}}
<br>
{{view App.SubInfoView}}
</script>
<script type="text/x-handlebars" data-template-name="subInfo">
<b>country:</b> {{country}}
</script>
{{view}}ヘルパの引数には、Viewクラスへのグローバルパスを指定します。
Viewクラス名が大文字で始まっていないと、Ember.jsはグローバルパスと認識しないようなので注意してください。
今回は子供Viewで参照するのは、元ViewであるUserViewのメンバなので、viewメンバ経由でなく、直接変数を参照しています。
このプログラムは以下のHTMLを出力します。(バインディングのためのマークは省略しています)
Albert Hofmann
<br>
<b>posts:</b> 25
<br>
<b>hobbies:</b> Riding bicycles
<br>
<b>country:</b> Japan
今日はViewを階層化する方法について見てきました。
変数のスコープの扱いが私の直感と違っていたため、理解するのに苦労しました。
このあたり、Ember.jsの学習の鬼門になりそうな気がします。
また、テンプレートから実際にはないメンバを指定した時にエラーなどを出力してくれないため、原因の特定に手間取りました。この奥ゆかしい挙動は、バグの原因特定を困難にするので、変えて欲しいところです。