DYSTOPIA

この記事は、 Sencha Advent Carendar 2014 の16日目の記事です。 @martini3oz がお届けします。

新しいことを覚えるというのは、大変ですが楽しいものです。

僕も先日、新しい体験をしました。THE KIDDIE というロックバンドのライブを観に行ったのです。 それはもう、これまで全然知らなかった世界でした。 とても新鮮でしたし楽しかった。KIDDIE サイコー。揺紗くんサイコー、ユウダイくんサイコー!

あ、Sencha の話でした…

Ext JS 5 から導入された ViewModel について、どのような使い方をして良いのかよくわからない、という話をよく聞きます。そこで、ViewModel について、解説したいと思います。

ViewModel は、View とデータバインディングするための仕組みです。 この DOM とデータの連携をする仕組みは、Sencha 以外のフレームワークでは大変ありがたく重要な機能のようですが、もともとコンポーネントベースで、データと画面表示の連携がすばらしい Sencha のフレームワークでは、「それって何が嬉しいの?」とか、「別にいらなくね?」という声も聞こえてきそうです。

そうはいっても、結構便利ですし、各コード量も減りますので、是非ご活用下さい。

bind

View に bind コンフィグを指定すると、そのコンフィグを、ViewModel の値とバインドできます。 バインドさせるときには、バインドさせたいコンフィグを bind で囲みます。 そして、値の名前を {} で囲んで指定します。

[js] bind: { title: ‘{title}’ } [/js]

残念ながら、bind 指定できるのは、全てのコンフィグではありません。 そのコンフィグに setter が存在しているもののみになります。 そりゃそうですよね、setter が無かったら値を設定できませんものね。

また、Sencha 得意のショートハンドというかシンタックスシュガーというかも用意されています。それが、defaultBindProperty です。コンポーネントによってあらかじめ決められたコンフィグは、bind と指定するだけで済みます。

例えば、TextField では defaultbindpropertyvalue なので、

[js] bind: { value: ‘{firstname}’ } [/js]

と書く代わりに

[js] bind: ‘{firstname}’ [/js]

と書けます。

bind に指定できるのは、ViewModel で管理している「値」です。その値には大きく3種類あります。

data

ViewModel の中で定義した data コンフィグの内容は、bind の値となる代表格です。

ViewModel

[js] data: { title: ‘Sencha Advent Carendar 2014’ } [/js]

View

[js] items: [{ xtype: ‘panel’, bind: { title: ‘{title}’ } }] [/js]

ViewModel の data コンフィグの中の値を、ビューのコンフィグにバインドしています。バインドするときには、bind で囲んでやります。

formulas

data は値そのものでしたが、formulas は計算式です。 関数の検査員結果を View にバインドさせるために使います。

[js] formulas: { fullName: function(get) { var firstName = get(‘rec.firstName’), lastName = get(‘rec.lastName’); return lastName + ‘ ‘ + firstName; } } [/js]

関数の引数として渡されるのは (上の例では get という名前になっています)、ViewModel の値を参照できる関数オブジェクトです。値の名前を渡してやると、その値を取得できます。 formulas は、他の書き方として、bind 指定で結びつける値を指定することもできます。

stores

ストアを ViewModel で管理します。stores で定義したストアを View の中にある、Grid や DataView とバインドすることができます。

Ext JS 4 までは、Application や Controller の stores コンフィグを指定すると、ストアのインスタンスをフレームワークが作成してくれましたが、それはアプリケーショングローバルでした。

ViewModel での stores 指定は、View とライフサイクルを共にする、ViewModel によって作られますので、このストアも View とライフサイクルを共にします。

[js] stores: { mystore: { type: ‘mystore’, autoLoad: true } } [/js]

このように指定します。 ストアの構造が結構複雑で、しかもいろんな ViewModel から使われるという場合は、app/store/ 下にストアのクラス定義を書いて、それを ViewModel の stores から利用することもできます。 その際には、ストアクラスで alias を指定して、ViewModel 側からは type 指定をすると便利です。

[js] Ext.define(‘MyApp.store.MyStore’, { extend: ‘Ext.data.Store’, // alias 定義 alias: ‘store.mystore’, model: ‘MyApp.model.MyModel’ }); [/js]

alias のプリフィックスは store です。

[js] // ViewModel では stores: { mystore: { type: ‘mystore’, autoLoad: true } } [/js]

reference

View のコンフィグに reference を指定すると、二ついいことがあります。 一つは、ViewController 内から簡単にコンポーネントの参照を取得できることです。 これは、一度取得したコンポーネントへの参照をキャッシュするようになっているので、ComponentQuery よりも高速にオブジェクトを取得できます。

もう一つは、バインドする値として、そのコンポーネントを使うことができる、ということです。 言っている意味がわからないと思うので、コードを見て下さい。

[js] Ext.define(‘Fiddle.view.MainModel’, { extend: ‘Ext.app.ViewModel’, alias: ‘viewmodel.myview’, data: { textvalue: ‘Sencha’ } }) Ext.define(‘Fiddle.view.Main’, { extend: ‘Ext.panel.Panel’, title: ‘MVVM way’, viewModel: ‘myview’, tbar: [{ xtype: ‘checkbox’, reference: ‘mycheck’ // reference を設定 },{ xtype: ‘textfield’, bind: { value: ‘{textvalue}’, hidden: ‘{mycheck.checked}’ // ここで使ってる! } }] }); [/js]

この例では Checkbox に reference を設定しています。 そして、TextField の hidden にバインドしているのです。 これで、イベントハンドラーを一行も書くことなく、テキストフィールドの表示を切り替える事ができます。

どうす?便利でしょ?

バインド時のオブジェクトの扱い

ViewModel のデータとバインドすると、データが変更されたときに画面が更新されますが、データが、ネストしたオブジェクトの場合には、少し注意が必要です。 ネストしたデータをずっと追いかけているとパフォーマンスの低下を招く場合があるので、標準では、オブジェクトのプロパティの変化はモニタリングされません。

つまり、

[js] data: { leader: ‘Kotsutsumi’ worker: { foo: ‘martini3oz’, bar: ‘tnker’ } } [/js]

こんなデータの場合、leader の値が変更された場合は、変更が検知されて表示が更新されますが、worker.foo の値が変更されたときには、変更は検知されず、画面が更新されません。

このような変更を検出するためには、View で bind 指定するときに、deep コンフィグを true に設定します。

[js] bind: { data: { bindTo : ‘{worker}’, deep : true } } [/js]

このように指定しますと、worker オブジェクトのプロパティに変更があった場合にも、このコンポーネントは更新されるようになります。

はい、ViewModel ご理解いただけましたか? 何か質問があったらコメントよろしくお願いします。

明日は、@kotsutsumi さんです。

1 thought on “DYSTOPIA

  1. ピンバック: Ext JS 5 データパッケージ | Sunvisor Lab. Ext JS 別館

コメントは停止中です。