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

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

仕様

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

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

まずは、model を作ります。

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

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

app/view/main/Main.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'
        }]
    });

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

app/view/list/List.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'
            }
        }
    });

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

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

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

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

app/view/list/ListModel.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'
                }]
            }
        }
    });

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

次に ViewController です。

app/view/list/ListController.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];
        }
    });

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

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

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

app/view/edit/Edit.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}'
        }]
    });

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

ViewModel を見てみましょう。

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

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

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

extjs5gridform

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

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

Ext JS 5 で ViewModel と ViewController を使ってみた。」への2件のフィードバック

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

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です