サンプル・アプリケーションの作成
これまでに紹介したDijitウィジェットに加え、レイアウト用ウィジェット利用してサンプル・アプリケーションを作ってみましょう。 作成するサンプル・アプリケーションはオンライン・ブックストアです。 このオンライン・ブックストアでは、商品選択画面と、カート画面があり、それぞれをタブで切り替えることができます。 各画面の概要は以下のとおりです。
商品選択画面:
画面左にある商品カテゴリーを利用して商品を選択します。選択された商品のイメージを右上部に、詳細情報を右下部に表示します。 購入予定数を入力して、「カートに追加」ボタンをクリックすると、選択されている商品をカートに追加します。
カート画面:
商品選択画面で選択した商品リストと合計金額を確認できます。 「会計」ボタンをクリックすると、カートの中の商品の会計処理を行います。 「クリア」ボタンをクリックすると、カート内の商品一覧をクリアすることができます。
このサンプル・アプリケーションでは、画面の構成の定義はwidgetPrimer-bookstore.htmlに、イベント・ハンドラーはwidgetPrimer-bookstore.jsに記述されています。以降の説明で登場するHTMLフラグメントはwidgetPrimer-bookstore.htmlを、JavaScriptはwidgetPrimer-bookstore.jsを参照してください。
画面のレイアウト
レイアウト用ウィジェットはdijit.layoutパッケージ内にあります。このサンプルアプリケーションでは、dijit.layout.TabContainerとdijit.layout.BorderContainerを使用します。 詳細情報やその他のウィジェットについては、dijit.layoutのAPIを参照してください。
まずは、dijit.layout.TabContainerを使用して、商品選択画面とカート画面を配置します。dijit.layout.TabContainerの子要素として、 商品選択画面(dijit.layout.BorderContainer)と画面(dijit.layout.ContentPane)を記述します。
<div dojoType="dijit.layout.TabContainer"> <div dojoType="dijit.BorderContainer" title="商品選択画面"> <!-- 商品選択画面 --> ... </div> <div dojoType="dijit.layout.ContentPane" title="カート"> <!-- カート画面 --> ... </div> </div>
dijit.layout.TabContainerは複数の子ウィジェットを持つことができます。 各子ウィジェットのtitle属性はタブページのタイトルとして表示されます。 上記のようにHTMLで宣言的に記述してタブページの構成を定義することもできますが、 プログラムで動的にページを追加することもできます。詳細については dijit.layout.TabContainerのAPIを確認してください。
次に商品選択画面のレイアウトを行います。商品選択画面は3つの部分で構成します。3つのペインのそれぞれは、商品カテゴリー画面(左側)、商品イメージ(右上部)、商品詳細画面(右下部)です。 dijit.layout.BorderContainerを使用してこれらのレイアウトを行うには以下のように記述します。
<!-- 商品選択画面 --> <div dojoType="dijit.layout.BorderContainer" design="sidebar"> <!-- 商品カテゴリー --> <div dojoType="dijit.Tree" region="left" splitter="true"> </div> <!-- 商品イメージ --> <div dojoType="dijit.layout.ContentPane" region="top" splitter="true"> </div> <!-- 商品詳細 --> <div dojoType="dijit.layout.ContentPane" region="center"> </div> </div>
BorderContainerウィジェットの各子要素にはregion属性を付加し、各子ウィジェットをBorderContainerのどこに配置するかを指定します。 全ての子ウィジェットでregion属性値を指定する必要があります。
BorderContainerのdesign属性には"headline"または"sidebar"を指定できます。design属性のデフォルト値は"headline"です。 "headline"は上下のペインが左右のペインの外側に表示されます。 商品カテゴリー画面を商品イメージ/詳細画面の左側に配置したいので"sidebar"スタイルを使用しています。
子ウィジェットのsplitter属性の値をtrueにすると、ペインのサイズを変更するリサイズハンドラーを付加することができます。 splitter属性はregion="center"以外の子ウィジェットに指定することができます。
イベント・ハンドラー
それでは、「カートに追加」ボタンにonClick属性を使ってイベント・ハンドラーを追加してみましょう。 「カートに追加」ボタンのイベント・ハンドラーは以下のように記述します。
<div dojoType="dijit.form.Button" onClick="sampleApp.product.onClickAddToCartButton"> カートに追加</div>
上記のようにonClick属性を指定することで、dijit.form.ButtonのonClickメソッドが呼ばれると、sampleApp.product.onClickTreeNodeが呼ばれます。
次はTreeウィジェットでの使用例です。Treeウィジェットのアイテムが選択されると、onClickメソッドが呼ばれます。 このonClickメソッドにイベント・ハンドラーを追加し、商品画面および商品詳細情報を更新するようにします。 「カートに追加」ボタンの例と同様の方法で、onClick属性にイベント・ハンドラー、sampleApp.product.onClickTreeNodeを指定しています。
<div dojoType="dijit.Tree" model="model" region="left" splitter="true" style="width: 25%;" onClick="sampleApp.product.onClickTreeNode"> </div>
次に確認ダイアログのOKボタンの例を見てみましょう。確認ダイアログのOKボタンでは、<script>を使用してイベント・ハンドラーを定義しています。 dijit.form.ButtonのonClickメソッドにコネクトするにはリスト12のように、type属性に"dojo/connect"、event属性にonClickを指定します。 そして<script>タグ内にイベント・ハンドラーを記述します。処理内容が単純であれば、処理内容を直接記述できるので便利です。
<div dojoType="dijit.form.Button">OK <script type="dojo/connect" event="onClick"> dijit.byId("confirmDlg").onCancel(); </script> </div>
Pub/Sub
サンプルアプリケーションでは、Pub/Subの機能を使ってカートへの追加処理とカート内のリストの更新を行っています。
まずはトピックを発行する側の実装方法を見てみましょう。「カートに追加」ボタンをクリックすると、sampleApp.product.onClickAddToCartButtonが呼ばれます。
onClickAddToCartButton: function(e) { var numOfProduct = dijit.byId("numOfProduct").get("value"); var msg = { id: sampleApp.product.currentProductId, num: numOfProduct }; dojo.publish("/sampleApp/addToCart", [msg]); }
このイベント・ハンドラーでは、"/sampleApp/addToCart"というトピックで、商品のIDと購入数を含むメッセージを発行しています。このトピック"/sampleApp/addToCart"のメッセージを購読するには以下のように記述します。
init: function() { var cartPane = dijit.byId("cartPane"); cartPane.subscribe("/sampleApp/addToCart", sampleApp.cart.addProductToCart); }
上記のように記述することで、メッセージが発行されると、イベント・ハンドラーsampleApp.cart.addProductToCartが呼ばれます。 sampleApp.cart.addProductToCartの実装は以下のようです。
addProductToCart: function(args) { var num = args.num; store.fetchItemByIdentity({ identity: args.id, onItem: function(item) { var label = store.getValue(item, "label"); var price = store.getValue(item, "price"); cartStore.newItem({name: label, price: price, num: num}); // WidgetのsetメソッドでWidgetのプロパティをセットします。 dijit.byId("clearListButton").set("disabled", false); dijit.byId("purchaseButton").set("disabled", false); cartStore.fetch({ onComplete: function(items) { var total = 0; dojo.forEach(items, function(item) { var num = cartStore.getValue(item, "num"); var price = cartStore.getValue(item, "price"); total += num * price; }); dojo.byId("total").innerHTML = total; } }); sampleApp.showSimpleDlg("カートに追加しました。", "確認"); } }); },
sampleApp.cart.addProductToCartでは、メッセージ内の商品IDと購入数から必要な情報を取り出し、カート内の商品一覧を更新します。 購入予定商品のリストはdojo.data.ItemFileWriteStoreで管理しDataGridで表示しています。 dojo.data.ItemFileWriteStoreおよびdojox.grid.DataGridに関する詳しい説明については、本連載の第2回および第3回で紹介していますのではここでは割愛します。