Ext JS 5 のViewModel を使ってみる

Ext JS 5 から導入された ViewModel を使ってみます。 ViewModel はデータをビューにバインドする新しい方法です。 いろいろと機能が高く、API ドキュメントやチュートリアルを読んでも、まだすべてが解説されているというわけではないようです。

今回は、2way binding と呼ばれる、View と ViewModel 間での双方向のデータバインディングについて実験してみます。 まずは、 Sencha Cmd 5.0 でプロジェクトを作ってみます。

$ sencha -sdk /path/to/sdk generate workspace ext5_ws
$ cd ext5_ws/ext
$ sencha generate app MyApp ../firstapp

以前と同じようにスケルトンのプロジェクトが生成されます。 スケルトンの中にも、すでに ViewModel が使われているのがわかります。 view/main ディレクトリの中に、Main.js の他に、MainController.js と MainModel.js があります。

Ext.define('MyApp.view.main.MainModel', {
    extend: 'Ext.app.ViewModel',

    alias: 'viewmodel.main',

    data: {
        name: 'MyApp'
    }

    //TODO - add data, formulas and/or methods to support your view
});

ここでは、name に MyApp を設定しています。

    items: [{
        xtype: 'panel',
        bind: {
            title: '{name}'
        },

View の方では、このようにパネルのタイトルにその値を、バインドしています。 これで、MainModel.js の方の、 data.name を変更してやると、表示も変わるのがわかります。

では、双方向のデータバインディングを実験してみます。

フォームを作ります。

スケルトンをまねて、view/form 下に Form.js / FormController.js / FormModel.js を作ります。

app/view/form/FormModel.js

Ext.define('MyApp.view.form.FormModel', {
    extend: 'Ext.app.ViewModel',

    alias: 'viewmodel.form',

    data: {
        name: '鬼瓦権三',
        zip: '999-9999',
        email: 'gonzo@example.com'
    }
});

これが ViewModel です。ここでは、data を定義しています。 alias コンフィグで、’viewmodel.hoge’ とすると、hoge がこの ViewModel の名前になります。

app/view/form/Form.js

Ext.define('MyApp.view.form.Form', {
    extend: 'Ext.form.Panel',
    xtype: 'app-form',

    requires: [
        'MyApp.view.form.FormModel',
        'MyApp.view.form.FormController'
    ],

    bodyPadding: 10,

    viewModel: {
        type: 'form'
    },

    controller: 'form',

    bind: {
        title: '{name}'
    },

    items: [{
        fieldLabel: '氏名',
        xtype: 'textfield',
        bind: '{name}'
    },{
        fieldLabel: '郵便番号',
        xtype: 'textfield',
        bind: '{zip}'
    },{
        fieldLabel: 'メール',
        xtype: 'textfield',
        bind: '{email}'
    }],
    tbar: [{
        text: '保存',
        handler: 'onSave',
        bind: {
            disabled: '{!name}'
        }
    }]
});

普通のフォームです。 ViewModel と、これから作る ViewController をrequires に入れています。 Main.js の所では requires に入れてないのにロードされています。これ不思議なんですよね。

  1. viewModel コンフィグで、ViewModel を指定しています。ViewModel の alias で定義したものですね。
  2. 同様に、controller コンフィグで、ViewController を指定しています。
  3. items 配列の中の、各フィールドに bind コンフィグで、ViewModel のデータをバインドしています。 このように、ブレスを使って定義するのは XTemplate と似ています。
  4. tbar コンフィグでツールバーを定義していますが、そこでも bind コンフィグを使っています。 これは、名前が入力されていない場合に、ボタンを disabled にするという指定です。
  5. またボタンのハンドラーには、文字列が設定されています。ViewController のこのメソッドが呼ばれます。

app/view/form/FormController.js

Ext.define('MyApp.view.form.FormController', {
    extend: 'Ext.app.ViewController',

    alias: 'controller.form',

    onSave: function () {
        console.log('Save Button Clicked!');
    }

});

こちらでは、onSave メソッドを定義しているだけです。 View の handler で文字列にて “onSave” を設定しましたから、このメソッドが呼び出されます。

app/view/main/Main.js
    requires: [
        'MyApp.view.form.Form'
    ],

    ....

    },{
        region: 'center',
        xtype: 'app-form'
    }]

Center リージョンのコンポーネントのタブパネルを削除して、このフォームを表示させます。 requires もわすれずに。

これで、ブラウザをリロードして結果を見てみましょう。

viewmodel

このように表示されます。 ViewModel の data がフォームフィールドにセットされているのがわかります。 このフォームでは、タイトルにも {name} がバインドされているので、name を変更すると、タイトルバーが自動的に変更されるのがわかると思います。

フォーム上のデータを書き換えて、コンソールに次の様に入力してみてください。

Ext.ComponentQuery.query('app-form')[0].getViewModel().getData()

data の内容が即座に変わっているのがわかります。

bind の定義は、

    bind: {
        title: '{name}'
    },

のように、bind のオブジェクトの中に、コンフィグのキーとバインドするプレースホルダをセットするのが普通だと思うのですが、field の部分では、 bind: '{name}' といきなりプレースホルダをセットできています。 このあたり、ちょっとまだわからないところがありますが、なかなかに便利そうな機能なので、調査していきたいと思います。

あと ViewModel と Store の関係についての記事も書きたいな。

Ext JS 5 のViewModel を使ってみる」への1件のフィードバック

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

コメントを残す

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