Ext JS 5 で ViewModel と ViewController を使ってみた。

Ext JS 5 の ViewModel / ViewController の使い方を検証してみました。 参考にしてください。

仕様

  • ユーザー一覧を Grid 表示する
  • Grid の行をダブルクリックしたらそのデータをフォームに表示する
  • フォームを編集するとグリッドに反映される

これを、ViewModel で備わった双方向データバインディングで実現させます。

まずは、model を作ります。

app/model/User.js
[js] Ext.define(‘Ext5.model.User’, { extend: ‘Ext.data.Model’, fields: [ ‘id’, ‘name’, ‘email’ ] }); [/js]

Sencha Cmd で generate したプロジェクトの view/main/Main.js を変更します。

app/view/main/Main.js
[js] Ext.define(‘Ext5.view.main.Main’, { extend: ‘Ext.container.Container’, requires: [ ‘Ext5.view.edit.Edit’, ‘Ext5.view.list.List’ ], xtype: ‘app-main’, layout: { type: ‘border’ }, items: [{ xtype: ‘component’, padding: 8, html: ‘My Ext JS 5 App’, region: ‘north’ },{ xtype: ‘mylist’, region: ‘center’ },{ xtype: ‘myedit’, width: 300, region: ‘east’ }] }); [/js]

同じディレクトリにある、MainModel.js と MainController.js はいらないので削除します。 items の 2つめと3つめのビューを作っていきます。

app/view/list/List.js
[js] Ext.define("Ext5.view.list.List",{ extend: "Ext.grid.Panel", xtype: ‘mylist’, controller: "list-list", // ViewControllerの指定 viewModel: { // ViewModelの指定 type: "list-list" }, bind: ‘{users}’, // データバインド columns: [{ dataIndex: ‘id’, text: ‘ID’ },{ dataIndex: ‘name’, text: ‘名前’, width: 300 },{ dataIndex: ‘email’, text: ‘メール’, width: 300 }], listeners: { // イベントリスナー itemdblclick: { fn: ‘onSelectItem’, scope: ‘controller’ } } }); [/js]

ごく普通の GridPanel です。 最初の方で、ViewController と ViewModel を指定しています。

bind: '{users}' という記述が見慣れないですね。 これが、データバインドです。この Grid に ViewModel の持っているデータをバインドします。 Grid の場合は、その対象はストアです。 このビューが持つ ViewModel に users という名前のストアがなくてはいけません。

listeners では、fn'onSelectItem' と文字列で指定しています。 scope: 'controller' の指定があるので、実際のリスナー関数は、ViewController が持っている onSelectItem メソッドになります。

次にこのビューの ViewModel を見てみます。

app/view/list/ListModel.js
[js] Ext.define(‘Ext5.view.list.ListModel’, { extend: ‘Ext.app.ViewModel’, alias: ‘viewmodel.list-list’, requires: [ ‘Ext5.model.User’ ], stores: { users: { model: ‘Ext5.model.User’, data: [{ id:1, name: ‘中村’, email: ‘nakamura@examplecom’ },{ id:2, name: ‘山田’, email: ‘yamada@examplecom’ },{ id:3, name: ‘田中’, email: ‘tanaka@examplecom’ },{ id:4, name: ‘佐藤’, email: ‘sato@examplecom’ },{ id:5, name: ‘齋藤’, email: ‘saito@examplecom’ }] } } }); [/js]

stores の中に users というキーの値としてオブジェクトリテラルをセットしています。 これで、Grid にバインドするストアを定義しています。 Ext JS 5 では、app/store 下にストアの定義を書くよりも、このように ViewModel の中でインスタンスを作る方法がメインになるようです。 ここでは、data コンフィグを使ってインラインでデータを指定しています。

次に ViewController です。

app/view/list/ListController.js
[js] Ext.define(‘Ext5.view.list.ListController’, { extend: ‘Ext.app.ViewController’, alias: ‘controller.list-list’, onSelectItem: function(grid, rec) { var me = this, form = me.getEditForm(); form.getViewModel().setData({rec: rec}); }, getEditForm: function() { return Ext.ComponentQuery.query(‘myedit’)[0]; } }); [/js]

ここで、onSelectItem メソッドを定義しています。 以前のコントローラーのように、control メソッドにどうこうという記述は不要です。

リスナーの中で、Edit ビューを取得して、その ViewModel にレコードをセットしています。 (ここのやり方はなんかイマイチだと思っています。もうちょっとスマートなやり方がありそう)

では、データをセットされる Edit ビューを見てみます。

app/view/edit/Edit.js
[js] Ext.define("Ext5.view.edit.Edit",{ extend: "Ext.form.Panel", xtype: ‘myedit’, viewModel: { type: "edit-edit" }, bodyPadding: 10, items: [{ xtype: ‘textfield’, fieldLabel: ‘ID’, bind: ‘{rec.id}’ }, { xtype: ‘textfield’, fieldLabel: ‘名前’, bind: ‘{rec.name}’ }, { xtype: ‘textfield’, fieldLabel: ‘メール’, bind: ‘{rec.email}’ }] }); [/js]

なんの変哲も無い FormPanel です。 ただ、ここも items の中に bind コンフィグがあります。

ViewModel を見てみましょう。

app/view/edit/EditModel.js
[js] Ext.define(‘Ext5.view.edit.EditModel’, { extend: ‘Ext.app.ViewModel’, alias: ‘viewmodel.edit-edit’, data: { rec: null } }); [/js]

これだけです。 この data コンフィグの中のものとビューがバインドします。 data コンフィグの中には rec があります。 この rec にレコード (モデルのインスタンス) をセットしてやると、フォームの方では、{rec.id} などとバインドさせているので、そのデータが表示されます。

これで、Grid の行をダブルクリックすると Form に内容が表示されます。 そこで、フォームの内容を書き換えると、リアルタイムで Grid の表示も変化するのがわかります。 これが双方向データバインディングです。

extjs5gridform

次の URL から Sencha Fiddle で実際の動きを見ることができます。

https://fiddle.sencha.com/#fiddle/6lp

2 thoughts on “Ext JS 5 で ViewModel と ViewController を使ってみた。

  1. ピンバック: Ext JS 5 資料リスト | Sunvisor Lab. Ext JS 別館

コメントは停止中です。