何を作るか?シンプルなフォトアルバムアプリを構築していきましょう。ページの下部には、写真のサムネールを横に並べます。ユーザが写真を選択するとURLが更新され、選択された写真がサムネールの並びの上に表示されます。シンプルなスライドショー機能も用意しましょう。4秒毎に次の写真に切り替えます。最終的なアプリケーションは図1のようになります。(クリックすると拡大)GitHubに最終的なソースコードが置いてあります。アプリケーション本体はそのsiteディレクトリにあります。アプリケーションを開始する方法にはいろいろありますが、シンプルなのは以下のやり方です。最終的なアプリケーション白紙の状態からはじめて、アプリケーションの機能を1つずつ構築していきましょう。アプリケーションのセットアップからです。プロジェクト構造とセットアップasdf-gemを使ってカレントディレクトリをホストする。詳しくはGitHubを参照。gemをインストールして、siteディレクトリでコマンド“asdf”を実行する。別のWebサーバを使って、アプリケーションをhttp://localhost/としてホストする。サンプルプロジェクトは図2のような構造になっています。外部ライブラリはすべて、site/scriptsディレクトリに置きます。必要なライブラリは以下の通りです。1.9.1imgディレクトリには10枚の画像ファイルがあり、これがフォトアルバムとして使われます。cssディレクトリにはmaster.cssというCSSファイルがあります。アプリケーションロジックはappディレクトリのいくつかのファイルに分かれています。app.jsファイルからはじめましょう。以後、アプリケーションに追加のファイルが必要になるたび、説明を加えていきます。バインディングの簡単な紹介Ember.jsでは、オブジェクト間の変数の値を同期するのにバインディングが使われます。リスト1のコードについて考えましょう。上のコードでは、jQuery、Handlebars、Ember.jsといったJavaScriptライブラリをインクルードする前に、まずCSSファイルをロードしています。アプリケーション本体は、10行目から25行目に定義されています。アプリケーションはその名前空間、BindingsExampleの定義からはじまっています。BindingsExample.personとBindingsExample.carという2つのオブジェクトを定義しています。Ember.jsの命名規則に従って、インスタンス化したオブジェクトの名前は小文字ではじめます。Skeie”をセットしています。carオブジェクトには、ownerBindingというプロパティがあります。プロパティを作ります。このプロパティはBindingsExample.person.nameプロパティの内容にバインドされます。Skeie”が出力されます。このやり方が美しいのは、BindingsExample.person.nameプロパティが変わると、Webサイトの内容も更新されるところです。ブラウザのJavaScriptコンソールに以下を入力して、Webサイトの内容が変わることを確かめてみましょう。dude”になります。このことを頭に入れて、サンプルアプリケーションを立ち上げていきましょう。Ember.jsアプリケーションの立ち上げどんなサンプルアプリケーションを構築するか感触を掴むため、最終的なアプリケーションを見てみましょう。空のindex.htmlファイルを作って、app、css、img、scriptsというディレクトリを追加しましょう。以下のファイルを作るかコピーしましょう。appディレクトリに、app.jsという名前のファイルを作る。cssディレクトリに、このファイルをコピーする。scriptsディレクトリに、Githubにあるファイルをコピーする。index.htmlファイルからはじめましょう。リスト2にあるように、スクリプトとCSSファイルを参照するだけです。最初のindex.htmlファイル最初にすべきことは、アプリケーションの名前空間をapp.jsに作ることです。いう名前空間を作ることにしました。app.jsファイルに以下を加えます。(EME)アプリケーションのオブジェクトモデルを定義する前に、CSSファイルにいくつか追加しておきましょう。背景を白色に、ボーダーを角丸にして、スクリーン全体をメインエリアで埋めることにします。css/master.cssファイルに以下を追加します。アプリケーションのmainAreaのCSSメインエリアを表示するために、index.htmlにリスト5を追加します。アプリケーションを保持するdiv要素の追加ページをリフレッシしましょう。画面全体に角丸の白いエリアが表示されるはずです。ここまで準備できたら、いよいよモデルを定義していきましょう。Dataによるオブジェクトモデルの定義まず、index.htmlファイルでインクルードしているscriptsのリストに、ember-dataを追加する必要があります(まだやっていなければ)。最初にデータストアを初期化する必要があります。app/app.jsを開いて、リスト6にある行を追加しましょう。データストアの作成ここではEME.storeという新しいDS.Storeオブジェクトを作っています。データストアには2つの情報を教える必要があります。Dataリビジョン番号、もう1つは使用するアダプタです。Dataに破壊的な変更があるのを知るためにあります。Dataはまだ未完成です。APIに達しておらず、最終リリースに向けてAPIが進化するにつれ、破壊的な変更が時々発生するためです。バックエンドとのインターフェイスには、DS.RESTAdapterを使うことにします。このアプリケーションに必要なのは、1種類のデータ、写真だけです。これには、id、title、URLという3つのプロパティがあります。DS.Modelを拡張することで、写真のデータモデルを定義します。models/photo_model.jsファイルを作成して、リスト7にあるコードを追加しましょう。写真のモデルオブジェクト"id"プロパティを定義していないことに気づいたかもしれません。Dataが作ってくれるためです。実のところ、自分で指定することは許されていません。ここでは、"imageTitle"と"imageUrl"という2つのプロパティを定義しています。いずれもDS.attr('string')によって、文字列として定義されています。離れて、アプリケーションの構造をどうするか、アプリケーションのURLをどう定義するかを考えましょう。StateManagerを使って、アプリケーションの状態を構造化しました。Routerという実装に置き換えられました。Routerはデフォルトで実行時に多数のボイラープレートコードを自動生成してくれます。これらは必要に応じて、簡単に上書きすることができます。アプリケーションを定義するためにまず必要なことは、それを組み立てるルートです。ルートをユーザの状態だと考えても構いません。各ルートには明確にURLが定義されています。Ember.jsはコントローラ、ビュー、テンプレートを自動生成します。事前に定義された基本機能では足らない場合には、独自の実装を作ることができます。Ember.jsは自動生成したコードをあなたの書いたコードに置き換えます。フォトアルバムの場合、全部で3つのルートが必要になります。先ほど述べたように、これらはEmber.jsが生成してくれるのですが、そのためにはまず、アプリケーションが必要としているルートをEmber.jsに教える必要があります。リスト8のようにEME.Router.map()を実装しましょう。router.jsという新しいファイルを作って、次のコードを追加します。アプリケーションルートの定義map()関数内には、2種類の関数が使われています。route()は最終ルートを表現しており、resource()はサブルートを含むルートを表現しています。URLに対応するphotosというリソースを定義しています。URLに対応するselectedPhotoというサブルートを作っています。Routerでは、コロンを前に付けたURL属性を使うことで動的部分を表します。Routerはこの部分を動的に置き換えます。Routerの命名規則により、:photo_idはEME.Photoモデルオブジェクトの"id"プロパティを参照していることに注意しましょう。URLをリクエストした場合には、indexルートからphotosルートにリダイレクトします。これはリスト9にあるようにEME.IndexRouteクラスを作ることで実現できます。これをrouter.jsファイルに追加しましょう。IndexからPhotosルートへのリダイレクトここではrouteのリダイレクト関数、transitionTo()関数を使ってphotosルートにリダイレクトしています。写真を見せるためにルートに必要な最後の部分は、どのデータを表示するかphotosルートに教えることです。以下のコードを使ってrouter.jsを拡張しましょう。Dataに任せて、サーバからEME.Photoオブジェクトを非同期に取得しています。サーバから応答が返ってくると、EME.PhotosRouteはPhotosControllerを自動生成し、データを入れてくれます。EME.Photo.find(1)にidを指定することで、サーバから特定の写真を問い合わせることもできますが、今回の場合はすべての写真を取得するので十分です。“/photos”から探します。その内容はリスト10のようになります。サンプルのフォトデータさて、写真をロードできたら、実際にそれを表示するコードが必要になります。アプリケーションにテンプレートを定義していきましょう。アプリケーションテンプレートの作成Ember.jsはデフォルトのテンプレートエンジンとしてHandlebars.jsを使っています。ここでは全部で4つのテンプレートを用意します。リスト5でアプリケーションテンプレートを見ましたが、これには重要なところが欠けています。それは現在のルートのテンプレートを描画するアウトレットです。リスト11のように、アプリケーションテンプレートを拡張することからはじめましょう。アウトレットを使ったアプリケーションテンプレートの拡張アウトレットは{{outlet}}という表現で定義され、Ember.jsにサブテンプレートを描画する場所を教えます。テンプレートの内容は現在閲覧されているルートによって変わります。indexルートの場合、このアウトレットにはindexテンプレートが含まれ、photosリソースの場合、photosテンプレートが含まれます。今回は写真のサムネールリストを描画するところなので、リスト12のようなphotosテンプレートを定義しましょう。photosテンプレートの定義ここには注意すべきことがいくつかあります。scriptタグにある"id"属性です。このid属性によって、Ember.jsにテンプレート名を教えます。このテンプレート名、photosは、このテンプレートがPhotosRouteに属することをEmber.jsに教えます。標準の命名規則に従っている限り、あとはEmber.jsがうまく面倒をみてくれます。このテンプレートで最初に定義しているのは、選択されている写真を描画する{{outlet}}です。それから、各サムネールを描画するdiv要素を定義しています。controller}}を使って、PhotosControllerにロードされた写真をイテレートしています。..}}を使って、各写真をselectedPhotoルートにリンクしています。リンクすべきルート(parent-route.sub.route経由)だけでなく、ルートに渡すコンテキストも指定していることに注意しましょう。この場合、コンテキストはユーザがクリックする写真になります。各サムネールを表示するためのカスタムビューを作りましょう。リスト13のような内容で、views/photo_thumbnail_view.jsファイルを作ります。サムネールのためのカスタムビューの作成PhotoThumbnailViewではまず、このビューがtagNameプロパティ経由でimgタグとして表示されることを指定しています。src属性とバインドし、このタグのCSSクラスであるthumbnailItemItを指定しています。どの写真が選択されているかがわかるよう、選択された写真を他の写真よりも大きくしましょう。CSSクラスを追加します。propertyが真を返す場合(ビューの写真idが選択された写真idと同じ場合)、CSSクラスis-selectedをビューに追加します。あと残っているテンプレートは、選択された写真の表示だけです。このルートはphotosリソースのサブルートなので、photos/selectedPhotoというidになります。selectedPhotoテンプレートをリスト14に示します。選択された写真のテンプレートこのテンプレートに新しいところはありません。選択された写真を置くためのdiv要素を表示するだけです。このテンプレートではタイトルと写真を表示します。アプリケーションをリロードしましょう。結果は図3のようになります。ここまでのフォトアルバム選択されている写真はハイライトされておらず、ほかのサムネールよりも大きくなっていないことに気づくかもしれません。それには、photosルートとselectedPhotosルートのためのコントローラを指定する必要があります。propertyを正しく解決できるよう、コントローラを関連付ける必要があります。それでは2つのコントローラを実装していきましょう。コントローラの定義photosリソースとselectedPhotoルートのために、カスタマイズしたコントローラを定義しましょう。photosコントローラをselectedPhotoコントローラと関連付ける必要があります。リスト15のようなcontrollers/photos_controller.jsファイルを作りましょう。PhotosControllerこの時点では、コントローラ内部にはほとんどなにもありません。コントローラをEmber.ArrayControllerとして定義したので、写真リストのテンプレートへのプロキシやバインディング、その他コントローラ関係の処理は、Ember.jsが面倒を見てくれます。指定しているのは、このコントローラがphotosSelectedPhotoControllerを必要とすることだけです。ここでコントローラ間の明示的な関係を指定したので、それが指しているコントローラも作る必要があります。リスト16のようなcontrollers/selected_photo_controller.jsファイルを作りましょう。PhotosSelectedPhotoControllerこのコントローラのカスタムロジックには何も実装していません。コントローラがEmber.ObjectControllerであることを指定して、宣言しているだけです。これは1つの写真のためのプロキシとして機能することを意味します。アプリケーションをリフレッシュすると、図4にあるように、選択された写真が期待通りにハイライトされます。コントローラ追加後あと残っているのは、ユーザによる写真の前後送り、スライドショーの開始停止のためのコントロールボタンです。選択された写真の下に、写真選択をコントロールするためのボタンを4つ追加します。“Play”ボタンはスライドショーを開始し、選択される写真を4秒毎に切り替えます。“Stop”ボタンは開始したスライドショーを停止します。“Next”と“Prev”ボタンはそれぞれ前後の写真を選択します。リスト17にあるように、まずはコントロールボタンを保持するphotoControlsというテンプレートを追加しましょう。選択された写真のテンプレートこのテンプレートは4つのボタンを生成しています。各ボタンに適切なアクションをアタッチしています。これらのアクション関数は後で実装することにします。このphotoControlsテンプレートをどこに表示するか、アプリケーションに教えましょう。このテンプレートは選択した写真のすぐ下に表示したいため、リスト18にあるようにphotosテンプレートの{{outlet}}のすぐ後に指定します。次に、4つのボタンのためのアクション関数を定義する必要があります。{{render}}表現を使っているため、私たちはPhotoControlsコントローラを生成して、photoControlsテンプレートのコントローラとして自動的に使わせることができます。controllers/photo_controls_controller.jsファイルを作りましょう。イベントをハンドルするPhotoControlsControllerの追加アプリケーションをリロードして、ブラウザコンソールを立ち上げると、ボタンをクリックするたびに、新たな行がコンソールに記録されるはずです。このコントローラはphotosControllerとphotosSelectedPhotoを必要としている、と指定していたことに注意しましょう。したのは、これら関数の内容をこのコントローラ内に実装するのではなく、ふさわしいコントローラに処理を委譲したかったためです。nextPhotoとprevPhotoはどちらもPhotosControllerにある方がふさわしいため、リスト20にあるように、このアクションをPhotosControllerに委譲するよう変更しましょう。PhotosControllerへのイベント委譲これは処理をPhotosControllerの関数に委譲しているだけです。関数の実装を詳しく見る前に、このコントローラを仕上げましょう。リスト20にあるようにスライドショー機能を実装します。スライドショー機能の追加ここで注意すべきことがいくつかあります。ユーザがPlayボタンをクリックすると、playSlideshow()関数がすぐに、次の写真を選択するためにnextPhoto()関数を呼び出します。それからJavaScriptに組み込まれているsetInterval()関数を使ってタイマーを開始します。この関数が返すidは、後でタイマーをクリアするのに使います。そのため、このidをPhotoControlsControllersのslideshowTimerIdプロパティに保持しておきます。私たちはタイマーがコールバック関数を実行するタイミングをコントロールしていないため、また、コールバックをEmber.jsの実行ループの一部として実行するため、コールバックの内容をEmber.run()にラップする必要があります。この時点でアプリケーションに欠けているのは、nextPhotoとprevPhoto関数の実装だけです。ここではnextPhotoの実装だけを示すことにします。いうのも実装はほぼ同じだからです。リスト21にnextPhotoの実装を示します。function選択されている写真がない場合、関数はリストの最初の写真を表示します。これはcontent.firstObjectプロパティを使ってphotos.selectedPhotoルートに遷移することで実現できます。写真が選択されている場合には、選択されている写真がcontent配列のどのインデックスにあるかを見つける必要があります。これはfindSelectedItemIndex()関数を呼び出すことで実現できます。リスト22にそれを示します。現在選択されている写真のインデックスがわかると、選択されているインデックスをインクリメントする必要があります。最後の写真が選択されている場合は例外です。このときにはcontent配列の最初の写真を選択する必要があります。遷移したい写真のインデックスが決まれば、その写真をコンテキストとして使って、photos.selectedPhotoに遷移するだけです。findSelectedItemIndex()関数findSelectedItemIndex()のコードには驚くようなところはないはずです。選択した写真が見つかるまでcontent配列をイテレートしているだけです。写真が見つからない場合には、content配列にある最初の写真のインデックスを返します。私は通常、自分のアダプタをapp.jsファイルには追加せずに、それ専用の.jsファイルに追加するようにしています。しておけば、後で実装を変えたいときに、アダプタのコードを見つけやすいためです。まとめEmber.jsは、クリーンで一貫性のあるアプリケーション開発モデルを提供します。理解しやすく、作成と更新が簡単な独自のテンプレートビューを作るのはとても簡単です。propertyを結びつけることで、Ember.jsはWebフレームワークに必要なボイラープレートコードを提供してくれます。使われている技術、DOMツリーの更新方法が非常に明確なので、サードパーティ製アドオンやプラグインを追加するのも簡単です。デフォルトで提供されるものでは不十分な場合も、Ember.jsの命名規則に従うことで、クラスを指定して実装するだけで済みます。この結果、テストしやすく、メンテナンスしやすいクリーンなコードになります。この記事がEmber.jsの開発モデルに対する理解を深め、次のプロジェクトでEmber.jsをどう利用できるか明確なイメージを描く助けになれば幸いです。Action"で詳しく説明しています。Publicationsのアーリーアクセスプログラムで入手できます。スタートできるということです。独立系コンサルタント、コースインストラクターに従事。アプリケーションプロファイルとオープンソースソフトウェアに強い関心がある。Toolの立ち上げに奔走している。haagen-software.noまで。Festに参加するとよいだろう。Joachim氏がその運営チームを引っ張っている。毎週火曜日に前週のまとめコンテンツがお送りいたします。25万人ものシニアデベロッパーのコミュニティーにぜひご参加ください。サンプルを見るあなたのメールアドレスはこちら国を選んでください。プライバシーポリシーに従って私の個人情報を扱うことに同意します。登録するとさまざまなことができます。アカウント登録をしてInfoQをお楽しみください。あなたの意見をお聞かせください。threadリスト5が表示されていません。/リスト5が表示されていません。/スパムの可能性があると認識されました。モデレーターが確認し問題がなければ24時間以内に公開します。その際あなたへの通知は行われませんのでご了承ください。書かれているタグがエスケープされていないようで、リスト5の内容が表示されていません。修正していただけると助かります。毎週火曜日に前週のまとめコンテンツがお送りいたします。25万人ものシニアデベロッパーのコミュニティーにぜひご参加ください。サンプルを見る様々なイノベーターとアーリーアダプターがお送りするテクノロジーの概要を見る。自分がまだ知らないことに気づいていないと知るあなたが興味のあるトピックスをいつでも最新な情報に。あなたのメールアドレスはこちら国を選んでください。プライバシーポリシーに従って私の個人情報を扱うことに同意します。よい世界へ私たちが暮らす世界を大切に思い、よりよいものにしたいと考えています。人のためのソフトウェア開発を加速し私たちのミッションを実現することで、この思いを成し遂げようとしています。私たちは利益の1%をさまざまな慈善団体に寄付しています。会社として、また従業員として、そうしたことの価値を強く信じているからです。with.プライバシーBTあなたのプロファイルは最新ですか?プロフィールを確認してアップデートしてください。アドレス*Eメールを変更すると確認のメールが配信されます。会社名:現在の会社名をご入力ください。Other組織規模:現在の組織規模をご入力ください。2,501+国:現在の国を設定してください。Zimbabwe都道府県:現在の都道府県に設定してください。次の都道府県にアップデートする:ニュースレターを購読しますか?インダストリーメールを購読しますか?本Eメールに登録すると、以前より関心のあったトピックの関連情報をお送りする場合がございます。詳細はこちらのプライバシーポリシーをご覧ください。newsletter?新しいメールアドレスに確認用のメールを送信します。このポップアップ画面は自動的に閉じられます。