本資料は、2011年12月18日に開催された株式会社ゼノフィ社内勉強会資料です。
アジェンダ
- TreeStoreを利用する
- コントローラー間のやりとり
「Ext JS 4.0/4.1 MVCアプリケーション構造の理解」の続きです。
ここからサーバーサイドも利用していきますが、シンプルにPHPで実装していきます。
TreeStoreを利用する
まず、ツリーを作成するためには、Ext JS 4 からTreeStoreを利用します。
とりあえず、サーバーサイドのPHPを提示します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
<?php $ret = array(<span style="color:#009900;">'items'</span> => array()); <span style="color:#000099;">if</span>(!isset($_REQUEST[<span style="color:#009900;">'node'</span>])) { $_REQUEST[<span style="color:#009900;">'node'</span>]=<span style="color:#009900;">'root'</span>; } <span style="color:#000099;">if</span>($_REQUEST[<span style="color:#009900;">'node'</span>]==<span style="color:#009900;">'root'</span>) { $ret[<span style="color:#009900;">'items'</span>] = array(array( <span style="color:#009900;">'id'</span>=><span style="color:#009900;">'menu1'</span>, <span style="color:#009900;">'text'</span>=><span style="color:#009900;">'メニュー1'</span> ), array( <span style="color:#009900;">'id'</span>=><span style="color:#009900;">'menu2'</span>, <span style="color:#009900;">'text'</span>=><span style="color:#009900;">'メニュー2'</span> )); } <span style="color:#000099;">else</span> { <span style="color:#000099;">switch</span>($_REQUEST[<span style="color:#009900;">'node'</span>]) { <span style="color:#000099;">case</span> <span style="color:#009900;">'menu1'</span>: $ret[<span style="color:#009900;">'items'</span>] = array( array( <span style="color:#009900;">'id'</span> => <span style="color:#009900;">'menu1-item1'</span>, <span style="color:#009900;">'text'</span> => <span style="color:#009900;">'アイテム1'</span>, <span style="color:#009900;">'leaf'</span> => <span style="color:#000099;">true</span> ) ); <span style="color:#000099;">break</span>; <span style="color:#000099;">case</span> <span style="color:#009900;">'menu2'</span>: $ret[<span style="color:#009900;">'items'</span>] = array( array( <span style="color:#009900;">'id'</span> => <span style="color:#009900;">'menu2-item1'</span>, <span style="color:#009900;">'text'</span> => <span style="color:#009900;">'アイテム1'</span>, <span style="color:#009900;">'leaf'</span> => <span style="color:#000099;">true</span> ) ); <span style="color:#000099;">break</span>; } } echo json_encode($ret); |
PHPのコードはプレーンな物で、単純にしてありますので、PHPの説明は省きます。
さて、まずは、上記のPHPスクリプトで読み込むべきストアを作成します。
src/app/store/Navi.js
1 2 3 4 5 6 7 8 9 10 11 |
Ext.define(<span style="color:#009900;">'Xenophy.store.Navi'</span>, { extend: <span style="color:#009900;">'Ext.data.TreeStore'</span>, proxy: { type: <span style="color:#009900;">'ajax'</span>, url : <span style="color:#009900;">'./navi.php'</span>, reader: { type: <span style="color:#009900;">'json'</span>, root: <span style="color:#009900;">'items'</span> } } }); |
viewやcontrollerと同じようにstoreというディレクトリ内に作成します。
このストアを利用するように、Naviコントローラーに設定を記述します。
src/app/controller/Navi.js
1 2 3 4 5 6 7 |
Ext.define(<span style="color:#009900;">'Xenophy.controller.Navi'</span>, { extend: <span style="color:#009900;">'Ext.app.Controller'</span>, stores: [<span style="color:#009900;">'Navi'</span>], init: <span style="color:#000099;">function</span>() { } }); |
storesに先ほど定義したStoreクラスを指定します。
ここに定義すればviewsのように自動的にExt.Loaderが読み込みを行います。
次に、viewのNaviパネルを、TreePanel(Ext.tree.Panel)に変更してストアを設定します。
src/app/view/Navi.js
1 2 3 4 5 6 7 8 |
Ext.define(<span style="color:#009900;">'Xenophy.view.Navi'</span>, { alias: <span style="color:#009900;">'widget.xenophy-navi'</span>, extend: <span style="color:#009900;">'Ext.tree.Panel'</span>, title: <span style="color:#009900;">'Navi'</span>, store: <span style="color:#009900;">'Navi'</span>, rootVisible: <span style="color:#000099;">false</span>, animate: <span style="color:#000099;">false</span> }); |
ここまでを実装すると、次のようにツリーが表示できるようになります。
リロードを実装する
TreeStoreを利用して、データをロードしてツリーを表現できました。
特にデータは変わりませんが、リロードボタンを実装してみます。
右上の「ボタン3」に実装しましょう。
まぁ、まずは、Headerコントローラーのcontrolメソッド内に実装します。
1 2 3 4 5 6 7 8 |
<span style="color:#009900;">'xenophy-header button[action=button3]'</span>: { click: <span style="color:#000099;">function</span>() { <span style="color:#000099;">var</span> navi = <span style="color:#000099;">this</span>.getNavi(); navi.getStore().load(); } } |
ボタンを押すと、ツリーがリロードされます。
Naviコンポーネントを取得するには、前にやったrefsのgetNaviを利用します。
TreePanelのストアにアクセスするには、
1 |
this.getNavi().store |
としてもアクセスできてしまします。
しかし、これは公開プロパティではありません。
なので、getStoreを呼び出して取得します。
1 |
this.getNavi().getStore() |
あとは、ストアのloadメソッドを呼び出すだけです。
さて、Treeパネル(Navi)を捕まえて、ストアオブジェクトを捕まえて、メソッドで操作することやってみました。
次に、同じ機能をNaviパネルにも実装します。
src/app/view/Navi.jsにボタンを追加します。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
Ext.define(<span style="color:#009900;">'Xenophy.view.Navi'</span>, { alias: <span style="color:#009900;">'widget.xenophy-navi'</span>, extend: <span style="color:#009900;">'Ext.tree.Panel'</span>, title: <span style="color:#009900;">'Navi'</span>, store: <span style="color:#009900;">'Navi'</span>, rootVisible: <span style="color:#000099;">false</span>, animate: <span style="color:#000099;">false</span>, tbar: [{ xtype: <span style="color:#009900;">'button'</span>, action: <span style="color:#009900;">'reload'</span>, text: <span style="color:#009900;">'リロード'</span> }] }); |
これまでの流れのように、このリロードボタンの実装を行うには、Xenophy.controller.Naviに実装します。
src/app/controller/Navi.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
Ext.define(<span style="color:#009900;">'Xenophy.controller.Navi'</span>, { extend: <span style="color:#009900;">'Ext.app.Controller'</span>, refs: [{ ref: <span style="color:#009900;">'navi'</span>, selector: <span style="color:#009900;">'xenophy-navi'</span> }], stores: [<span style="color:#009900;">'Navi'</span>], init: <span style="color:#000099;">function</span>() { <span style="color:#000099;">var</span> me = <span style="color:#000099;">this</span>; me.control({ <span style="color:#009900;">'xenophy-navi button[action=reload]'</span>: { click: <span style="color:#000099;">function</span>() { <span style="color:#000099;">this</span>.getNavi().getStore().load(); } } }); } }); |
さて、ここまでで2カ所リロードする処理を実装しました。
・・・・1カ所にしたくないでしょうか?
同じことやってるんですかね。
次の項目で、この処理を統合しましょう。
コントローラー間のやりとり
さて、Headerでもリロードを実装し、Naviでもリロードを実装しました。
Naviのリロードですから、Naviのコントローラーにだけ実装したいですね。
ということは、Headerコントローラーから、Naviコントローラーにアクセスする手段が必要です。
まずは、Naviコントローラーの実装をメソッド化します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
Ext.define(<span style="color:#009900;">'Xenophy.controller.Navi'</span>, { extend: <span style="color:#009900;">'Ext.app.Controller'</span>, refs: [{ ref: <span style="color:#009900;">'navi'</span>, selector: <span style="color:#009900;">'xenophy-navi'</span> }], stores: [<span style="color:#009900;">'Navi'</span>], init: <span style="color:#000099;">function</span>() { <span style="color:#000099;">var</span> me = <span style="color:#000099;">this</span>; me.control({ <span style="color:#009900;">'xenophy-navi button[action=reload]'</span>: me.onReload }); }, onReload: <span style="color:#000099;">function</span>() { <span style="color:#000099;">this</span>.getNavi().getStore().load(); } }); |
次に、Headerコントローラーのリロード実装を、NaviのonReloadの呼び出しに切り替えます。
ボタン3の実装を次のように切り替えます。
1 2 3 4 5 6 7 |
<span style="color:#009900;">'xenophy-header button[action=button3]'</span>: { click: <span style="color:#000099;">function</span>() { <span style="color:#000099;">this</span>.getController(<span style="color:#009900;">'Navi'</span>).onReload(); } } |
はい、getControllerを使って引数に、ほしいコントローラー名をいれるだけですね。
こちらの方が正しいのですが、コントローラーはMixedCollectionで管理されています。
次のようにアクセスすることも可能です。
1 |
this.application.controllers.get('Navi') |
コントローラーオブジェクトを取得するがために、ややこしい実装を自分でする必要は一切ありません。
イベント化
さて、NaviコントローラーのonReloadをHeaderコントローラーで直接呼び出しました。
Ext JS らしくイベントで処理するように修正してみましょう。
ボタン3のイベントハンドラを次のように書き換えます。
1 2 3 4 5 6 7 |
<span style="color:#009900;">'xenophy-header button[action=button3]'</span>: { click: <span style="color:#000099;">function</span>() { <span style="color:#000099;">this</span>.getHeader().fireEvent(<span style="color:#009900;">'doReloadNavi'</span>); } } |
次に、Naviコントローラーを次のように書き換えます。
src/app/controller/Navi.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
Ext.define(<span style="color:#009900;">'Xenophy.controller.Navi'</span>, { extend: <span style="color:#009900;">'Ext.app.Controller'</span>, refs: [{ ref: <span style="color:#009900;">'navi'</span>, selector: <span style="color:#009900;">'xenophy-navi'</span> }], stores: [<span style="color:#009900;">'Navi'</span>], init: <span style="color:#000099;">function</span>() { <span style="color:#000099;">var</span> me = <span style="color:#000099;">this</span>; me.control({ <span style="color:#009900;">'xenophy-header'</span>: { doReloadNavi: me.onReload } }); }, onReload: <span style="color:#000099;">function</span>() { <span style="color:#000099;">this</span>.getNavi().getStore().load(); } }); |
はい、xenophy-header(xtype)で、コンポーネントを捕まえて、イベントハンドラをonReloadを設定するだけですね。
こうすることで、Headerパネルとコントローラーが、Naviツリーパネルに依存しなくなります。
(コンポーネントとして独立して動作するということ、コンポーネント別テストなどに非常に有効です)
コントローラーオブジェクトを取得して、処理をすべきか、イベントで処理すべきかは設計次第ですが
通常はイベントで行うべきです。
グループ化されたコンポーネント(複数のコンポーネントが必ずないと動かない前提のコンポーネント)の場合
複数コントローラーになることもありますので、その場合にはgetControllerで処理しても問題ないでしょう。
終わりに
ツリーパネルをExt JS 4で、かつMVCでどのように操作するかが理解できたのではないでしょうか。
Ext JS 4.0/4.1 MVCアプリケーション構造の理解IIIでは、Centerパネル内に、FormパネルとGridパネルを作成して、ナビゲーションから切り替える操作を実装していきながら、GridパネルとFormパネルの操作も習得していきましょう。
Pingback: Hotels in Gold Coastmotel discountslate hotel resort specials.