実践入門 Ember.js

第4回 ユーザのインタラクション(Controller, Component)

この記事を読むのに必要な時間:およそ 6 分

前回は画面遷移について解説しました。 今回はデータを画面に表示するところから一歩進んで, ユーザのインタラクションを受け取って画面を更新する方法を解説します。

今回は次のEmber.jsアプリケーションの仕組みを理解することを目標にします。

『記事が長い場合は途中から省略して「もっと読む」をクリックすると続きが表示される』というアプリケーションです。

前準備

本稿の対象バージョンはこちらです。

前回の記事と本稿執筆時点でのEmber.jsの最新バージョンは同じです。 前回の記事を参考にして必要なファイルを作成してください。

ファイルの作成が完了したら,次は今回の解説の基礎となるルーティングとテンプレートを準備します。

ルーティング

App = Ember.Application.create();

App.Router.map(function() {
  this.resource('posts', {path: '/'}, function() {
    this.route('show', {path: '/posts/:post_id'});
  });
});

App.PostsRoute = Ember.Route.extend({
  model: function() {
    return [{
      id: 1,
      title: 'Ember.js 公式サイトの歩き方',
      body: 'Ember.js の公式サイト(http://emberjs.com/)では、まずトップページのサンプルを動かしてみるとよいでしょう。Ember.js でどんなことができるのかがざっくりわかります。'
    }, {
      id: 2,
      title: 'Ember.jsのディスカッションフォーラム',
      body: 'Ember.js についての疑問・質問・新しい提案など、Ember.js に関することが常に議論されています。 http://discuss.emberjs.com/'
    }];
  }
});

App.PostsShowRoute = Ember.Route.extend({
  model: function(params) {
    return this.modelFor('posts').filter(function(post) {
      return post.id === Number(params.post_id);
    })[0];
  }
});

テンプレート

<script type="text/x-handlebars" data-template-name="posts/index">
  <ul>
    {{#each post in model}}
      <li>{{link-to post.title "posts.show" post}}</li>
    {{/each}}
  </ul>
</script>

<script type="text/x-handlebars" data-template-name="posts/show">
  <h2>{{model.title}}</h2>

  <pre>
    {{model.body}}
  </pre>

  {{link-to "戻る" "posts.index"}}
</script>

さて,ここまでで記事が画面が表示されるようになりました。

ではここから,記事が長い場合に省略して表示するようにしましょう。

Controller

記事の詳細画面では「記事の全文を表示しているか,それとも省略して表示されているか」というフラグをどこかに持っておく必要があります。 そこで今回解説するのがControllerです※1)⁠コントローラは,URLともmodelとも関係のない一時的なデータを保持できます。

※1
「Controller」という単語はクライアントサイドMV*のライブラリに登場することが多いですが,その意味合いは各ライブラリ/フレームワークによってまちまちです。そのため,Ember.js以外のライブラリを扱ったことがある方は,それとはまったく別のものと考えて読み進めてください。

これだけではイメージしづらいので,コントローラについて詳しく見ていきましょう。

Routeが画面を描画する際,modelと一緒にコントローラも準備されます。 そしてコントローラのmodelプロパティにRouteで解決されたmodelが設定され, その状態でコントローラがテンプレートに描画されます。 テンプレートのコンテキストは,実はこのコントローラだったのです。

テンプレートではコントローラのプロパティにアクセスできるため,モデルにアクセスしたい場合はmodelをつけてプロパティを参照していました。

<h2>{{model.title}}</h2>

<pre>
  {{model.body}}
</pre>

つまり,コントローラ自身にプロパティを設定することで,そのプロパティをテンプレートから参照できることになります※2)⁠

※2
本連載ではEmber.Controllerを利用していますが,Ember.jsにはEmber.ObjectControllerというコントローラも用意されています。ObjectControllerはmodelプロパティへのプロキシとして振る舞うため,これを使うとmodelプロパティの記述を省略できます。ただ,むやみに省略してしまうと,テンプレートを見た時にプロパティの定義元が分かりづらくなるという弊害があります。そのため,ObjectControllerはEmber.js 1.11.0では非推奨になり,Ember.js 2.0では削除される予定です。既存のEmber.jsの紹介記事ではObjectControllerを取り扱うものも多いですが,本連載ではControllerを取り扱うことにします。また,modelが配列のときに利用するEmber.ArrayControllerというコントローラも存在します。

さっそく次のコードを追記して確認してみましょう。

コントローラ

App.PostsController = Ember.Controller.extend({
  pageTitle: 'Ember.js 関連の記事'
});

テンプレート

<script type="text/x-handlebars" data-template-name="posts">
  <h1>{{pageTitle}}</h1>

  {{outlet}}
</script>

コントローラのプロパティであるpageTitleが画面に表示されていますね。

ちなみに,Route名とコントローラ名の対応はEmber Inspectorで確認できます。 また,Route名に対応しないコントローラを利用したい場合,RoutecontrollerNameを設定することで変更可能です。

App.SomeRoute = Ember.Route.extend({
  controllerName: 'other'
});

この例の場合,App.SomeRouteのコントローラとしてApp.OtherControllerが設定されます。

Handlebars Helpers

では「記事を省略して表示をするかどうか」というフラグをコントローラにもたせて,⁠もっと見る」というリンクをクリックした際にその情報を更新することにします。

次のコントローラを作成してください。

App.PostsShowController = Ember.Controller.extend({
  isExpanded: false
});

テンプレートを書き換えてください。

<script type="text/x-handlebars" data-template-name="posts/show">
  <h2>{{model.title}}</h2>

  <pre>
    {{#if isExpanded}}
      {{model.body}}
    {{else}}
      {{truncate model.body length=20}}
    {{/if}}
  </pre>

  {{link-to "戻る" "posts.index"}}
</script>

{{truncate model.body length=20}}の部分は独自に定義したヘルパーを利用しています。 そのため,その定義を記述しておきましょう。

Ember.Handlebars.helper('truncate', function(value, options) {
  var length = options.hash.length;

  if (value.length > length) {
    return value.slice(0, length) + '...';
  } else {
    return value;
  }
});

ヘルパーの定義

Ember.Handlebars.helperで定義したヘルパーはテンプレートで利用できます。 ヘルパーの書式は次の通りです。

{{ヘルパー名 (引数1 引数2 ...) (オプション)}}
ヘルパー名

Ember.Handlebars.helperでヘルパーを定義する際に指定したヘルパー名です。

引数

ヘルパー関数の引数です。

オプション

key=valueの形で指定します,必要に応じていくつでも設定できます。ヘルパー関数では,一番最後の引数のhashプロパティから取得できます。

さて,ここまでで記事の本文が一定文字数を超える場合は「…」で表示されるようになりました。 次は,⁠もっと見る」リンクを作成してみましょう。

著者プロフィール

佐藤竜之介(さとうりゅうのすけ)

株式会社えにしテック所属。JavaScriptとRubyが好きなウェブ系プログラマ。オープンソースソフトウェアに強い関心がありEmber.jsにも数多くのパッチを送っている。

ブログ:http://tricknotes.hateblo.jp/
Twitter:@tricknotes

コメント

コメントの記入