リスト表示 – Ember.js入門(7)

2013.10.02

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

アプリケーションでは、しばしば取得した情報の一覧を表示します。Ember.jsではモデルに配列を指定する事で、簡単に一覧表示を行うことができます。

リストを表示する簡単な例

簡単な例として、メンバーの一覧を表示するアプリケーションを作成します。本来は、メンバーの一覧はサーバから取得しますが、ここでは簡単にクライアントのみで完結するように定義しました。また、画面遷移はないため、デフォルトとなるApplicationRouteのmodelでオブジェクトの配列を返します。

window.App = Ember.Application.create();
App.ApplicationRoute = Ember.Route.extend({
  model: function(params) {
  	return [
  	  {name: '百田夏菜子', color:'レッド' }, 
  	  {name: '玉井詩織',  color:'イエロー' },
  	  {name: '佐々木彩夏', color:'ピンク' },
  	  {name: '有安杏果',  color:'グリーン' },
  	  {name: '高城れに',  color:'パープル' },
  	];
  },
});

これを表示するテンプレートです。

	<script type="text/x-handlebars">
    <ul>
    {{#each}}
      <li>{{name}}({{color}})</li>
    {{/each}}
    </ul>
	</script>

表示結果はこのようになります。

Listing_-_Ember.js

非常にシンプルなんですが、暗黙的すぎて気持ち悪いです。今回はこの挙動に関して解説します。

ApplicationRouteとApplicationController

はじめに暗黙的に作成されるRouteとControllerについて補足します。

Ember.jsでは幾つかのRouteやControllerが暗黙的に作成されます。ApplicationRouteApplicationControllerはその代表的なもので、すべてのRouteとControllerの基底クラスとして作成されます。もし、Routerにrouteのマッピングを行わない場合は、デフォルトのApplicationRouteが選択され、デフォルトのtemplateでレンダリングされます。この時のControllerはApplicationControllerです。

Ember.jsにはControllerの基底クラスとして、Ember.ObjectControllerEmber.ArrayControllerがあります。名前から解るように、前者はモデルが通常のオブジェクトの場合に利用するControllerで、後者はモデルが配列の場合に利用するControllerです。サンプルのようにApplicationControllerを明示的に定義しない場合、モデルの型から自動的にControllerの種類が選択されます。この場合は、モデルが配列なのでEmber.ArrayControllerです。

明示的に書く場合は次のように定義します。

App.ApplicationController = Ember.ArrayController.extend({
});

しかし、次のように定義すると、エラーとなります。

App.ApplicationController = Ember.ObjectController.extend({
});

今回はControllerに何もアクションや状態を定義していませんが、通常はなんらかの追加機能を実装するでしょう。したがって、常に明示的に記述した方がはまりにくいです。

これは、ApplicationRouteなどにも同じ事がいえます。Ember.jsは、暗黙的に色々なオブジェクトを作成しますが、黒魔術すぎてはまる原因になります。特に慣れるまでは、ひとつひとつ丁寧に明確に宣言していった方がよいと思います。

eachヘルパー

テンプレートを見ると、次のような繰り返し処理が記述されています。

    {{#each}}
      <li>{{name}}({{color}})</li>
    {{/each}}

このeachは、オブジェクトを繰り返しレンダリングするためのヘルパーです。しかし、なにを繰り返すのかが省略されています。

Ember.jsではレンダリング時にどのコンテキストであるかが重要な要素となっています。この個所ではコンテキストはデフォルト状態になっているのでApplicationControllerです。したがって、eachヘルパーはApplicationControllerに適用されます。ApplicationController自体はEmber.ArrayControllerを継承したクラスであるため、モデルである配列に対して、処理が繰り返されます。

eachの内部では、コンテキストは繰り返されるオブジェクトに変わります。このため、{{name}}や{{color}}は各オブジェクトに対するプロパティとして作用します。このため、eachの内部で{{member.name}}といった冗長な記述をしなくて済むようになっています。

でも、ぶっちゃけ解りにくいです。

eachの対象を明確にする

eachの対象を明確にするのであれば、次のようにmodelをパラメータとして指定します。modelはApplicationControllerのプロパティで、ApplicationRouteのmodelメソッドで返すモデルが対応します。

    {{#each model}}
      <li>{{name}}({{color}})</li>
    {{/each}}

each内でコンテキストを変えない

eachを使うとコンテキストが繰り返されるオブジェクトに変わるのは便利です。しかし、親要素の情報も合わせて表示したい場合など、コンテキストを変えると困る場合もあります。そのような場合はeachにinを組み合わせます。

    {{#each member in model}}
      <li>{{member.name}}({{member.color}})</li>
    {{/each}}

このようにinを利用すると、コンテキストが変わらないため、親要素の情報も繰り返し処理の中で参照できます。ただし、やや冗長になります。

まとめ

Ember.jsはリストの表示も簡単に出来る強力なMVCフレームワークです。しかし、暗黙的に作成されるオブジェクトやレンダリング時のコンテキストなどクセの強い部分もあり、嵌まりやすいポイントが多いです。しっかりと仕組みを理解して活用しましょう。

最後にコード全体を示します。

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Listing - Ember.js</title>
</head>
<body>
	<script type="text/x-handlebars">
    <ul>
    {{#each model}}
      <li>{{name}}({{color}})</li>
    {{/each}}
    </ul>
	</script>
	<script type="text/javascript" src="js/libs/jquery-1.9.1.js"></script>
	<script type="text/javascript" src="js/libs/handlebars-1.0.0.js"></script>
	<script type="text/javascript" src="js/libs/ember-1.0.0.js"></script>
	<script type="text/javascript">
window.App = Ember.Application.create();
App.ApplicationRoute = Ember.Route.extend({
  model: function(params) {
  	return [
  	  {name: '百田夏菜子', color:'レッド' }, 
  	  {name: '玉井詩織',  color:'イエロー' },
  	  {name: '佐々木彩夏', color:'ピンク' },
  	  {name: '有安杏果',  color:'グリーン' },
  	  {name: '高城れに',  color:'パープル' },
  	];
  },
});
App.ApplicationController = Ember.ArrayController.extend({
});
	</script>
</body>
</html>