ItemController – Ember.js入門(13)

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

渡辺です。新年早々ですが、ガツガツいきましょう。

今回は、ItemControllerを紹介します。ItemControllerは、リスト表示などを行う時、モデルの情報を加工した値や、Viewに依存した値を出力するためによく使われます。しかし、ItemControllerは、Ember.jsでも利用頻度も高く非常に便利な機能なのですが、公式ドキュメントではチュートリアルにさらりと書いてあるだけでAPIドキュメントにしか記述されていないため、見つけにくい機能かもしれません。

ItemControllerとは?

前回のObjectControllerとArrayController – Ember.js入門(12)では、ArrayControllerを解説しました。ArrayControllerはModelが複数の場合に利用するControllerで、View(テンプレート)ではeachヘルパーによる反復表示を行うことができます。

App.ApplicationRoute = Ember.Route.extend({
    model: function() {
        return [
            {name: 'サッポロクラシック', unitPrice: 250, quantity: 5},
            {name: 'ニッカ余市', unitPrice: 2200, quantity: 1},
            {name: '小樽ワイン', unitPrice: 950, quantity: 2}
        ];
    }
});
App.ApplicationController = Ember.ArrayController.extend({
});

<script type="text/x-handlebars">
<h2 id="toc-">ご注文</h2>
<ul>
{{#each}}
  <li>{{name}}</li>
{{/each}}
</ul>
</script>

この時、eachの内部ではモデルのプロパティにアクセスできますが、Computed Propertyを利用するにはModelに定義しなければなりません。Modelに相応しいComputed Propertyであれば問題ありませんが、Viewに依存するようなCSSのクラス名などをModelに定義するのはよろしくありません

このような場合に、eachの内部で局地的に適用できるControllerがItemControllerです。

ItemControllerの定義

ItemControllerは通常のControllerと同様に、Ember.ObjectControllerのサブクラスとして定義します。ItemControllerには利用される時にeachで反復処理される個々のModelがコンテキストオブジェクトとして設定されることを前提にComputed Propertyなどを定義します。次のコードでは、ModelのunitPriceプロパティとquantityプロパティを掛けた値をsubtotalとして定義しています。

App.OrderController = Ember.ObjectController.extend({
    subtotal: function() {
        return this.get('unitPrice') * this.get('quantity');
    }.property('unitPrice', 'quantity')
});

Ember__ItemController

ItemControllerの指定

ItemControllerを利用する方法は2つあります。

eachヘルパーのitemController属性に指定する

ひとつ目の方法はeachヘルパーのitemController属性に指定する方法です。

<ul>
{{#each itemController="order"}}
  <li>{{name}} - ¥{{subtotal}}(¥{{unitPrice}}×{{quantity}})</li>
{{/each}}
</ul>

eachで反復されるのはControllerのコンテキストオブジェクトとなる配列です。それぞれの要素がitemControllerで指定されたControllerのコンテキストオブジェクトとなります。したがって、Modelの各プロパティにアクセス可能で、かつItemControllerに追加されたComputed Propertyなどにもアクセスできます。

なお、itemController属性に指定する場合、クラス名(App.OrderController)ではなくlookup名(小文字始まりでControllerをつけない形式)で指定します。

ArrayControllerのitemControllerプロパティに指定する

ItemControllerはArrayControllerのitemControllerプロパティに指定することもできます。

App.ApplicationController = Ember.ArrayController.extend({
    itemController: "order"
});

効果についてはeachヘルパーの場合と変わりません。

この場合、eachヘルパーのitemController属性を指定しなくともOrderControllerが利用されます。もし、両方が指定されていたならばeachヘルパー側が優先されます。

まとめ

ItemControllerは反復処理対象のModelに対し、個々の独立したControllerを提供します。したがって、ArrayControllerでModel毎のComputed Propertyを定義する時に便利に利用することができます。また、ItemControllerは通常のControllerと同じだけの機能を持ちますので、Model毎の状態やactionを定義することも容易です。ItemControllerを活用し、粒度が揃ったEmber.jsのコードを構築してください。