Ext JS 5 データパッケージ

Sencha Advent Calendar 2014 も残すところ、2つとなりました。

もちろん、大トリは、@kotsutsumi さんですので、私が前座を取らせてもらいます。

この前の記事でご紹介した THE KIDDIE ですが、あのあとも色々と聴いているんですが、いいんですよ。楽曲もいいし、歌うまいし。皆さんも聴いてみて下さい。 最新曲 OMELAS の PV がこちらです。明日は、渋谷公会堂でライブです。行きたかったなぁ〜。

僕が、お気に入りなのは「溜息の呪文」て曲ですので、今回のまくらでは Sencha な呪文ぽい話をしようかなと思います。

Sencha Cmd 5 と、Sencha Ext JS 5 で開発していると、 bootstrap.json とかの変更が頻繁に必要になります。 いちいちやるのはめんどくさいので、ここは、Sencha が推奨するように、「ウォッチ」を起動しましょう。

違〜う。それじゃない。

呪文その1

[bash] sencha app watch [/bash]

app watch は、 Sencha Cmd 4 からありましたが、5 では進化しています。 Sencha Cmd 5 では、これでプロジェクト ディレクトリの監視もしながら、Web サーバーも立ち上げてくれます。 開発中のプロダクトが、サーバーサイドを必要としない、あるいは、外部のデータリソースを利用するような場合は、Cmd が起動する Web サーバーで十分に対応できるはずです。

そして、ファイルの変化を監視して、適切にビルド処理をしてくれます。 もちろん sencha app build をするよりもずっと素早くやってくれます。

呪文その2

もう一つの呪文は、

[bash] sencha app refresh [/bash]

です。 Ext JS 5 with Sencha Cmd 5 で開発をしている時には、この呪文を頻繁に唱えましょう。 それだけで結構スムースに開発が進みます。 「あれ?おっかしーな」 と思ったら

[bash] sencha app refresh [/bash]

なんか、新しいコンポーネントを足したら

[bash] sencha app refresh [/bash]

SASS ファイルにスタイル追加したら

[bash] sencha app refresh [/bash]

まずは呪文を唱えましょう。 あとね、

呪文その3

[bash] sencha app build develope [/bash]

というのが、ちょっと意味がある呪文のようです。

development ビルドは実際にはビルドしません。それをしない代わりに、ビルド前の状態に bootstrap.js などを戻してくれます。 アプリの開発途中で production や testing でビルドした後に、ビルトインコンポーネントのスタイルの一部が適用されなくなってしまった、なんてときにこの呪文を唱えると解決します。覚えておきましょう。

まくらは、ここまでにして、今日は Ext JS 5 のデータパッケージのお話をします。

Ext JS 5 データパッケージ

Ext JS 5 では、色々なところが、前のバージョンから大きく変わりました。 一つは、僕の前のエントリでもご紹介した、MVVM の導入です。 ViewModel と viewController によって、アプリケーションを構造化しやすくなりました。

次に挙げるとすると、Ext JS の真骨頂たるコンポーネント、Grid ですね。 Ext JS の Grid は花形コンポーネントですので、今回も沢山進化しています。 その一つは、昨日の Advent Calendar で、紹介されていますね。 5.1 で導入された、スプレッドシート セレクションモデルです。

このセレクションモデルや、クリップボード プラグインは、非常に便利で素晴らしい機能です。

このエントリでは、もうちょっと地味な所を取り上げます。

Ext JS になって、地味に変わったところは、データパッケージです。 ここの部分て、Ext JS の見た目系から入っていると何が嬉しいの?という世界ですが、実際に開発をしていると、こういった部分に助けられることの方が多いです。

今回のデータパッケージで変わったところはいくつかありますが、その中からいくつかのトピックを取り上げましょう。

フィールドには、多くの機能が加わりました。

convert / calculate

以前からあった convert メソッドに、depends 指定が加わりました。 convert メソッドは、サーバーからのレスポンスを、変換する関数で、モデルからそのフィールドを参照するときに、この関数が実行されて値が取り出されます。

[js] { name: ‘fullName’, convert: function(value, record) { return me.get(‘first’) + ‘ ‘ + me.get(‘last’); } } [/js]

こんな感じで使えるんですが、convert にはレコード (モデルのインスタンス) が丸ごと渡されるので、 どこかのフィールドがセットされる毎に convert を走らせる必要がありました。 dipends コンフィグを指定すると、

[js] { name: ‘fullName’, convert: function(value, record) { return me.get(‘first’) + ‘ ‘ + me.get(‘last’); }, depends: [‘first’, ‘last’] } [/js]

指定したフィールドに変化があったときだけ、convert が実行されるようになり、効率がアップします。 でも、もっと便利な指定方法も追加されました。それは、caluculate メソッドです。

[js] { name: ‘fullName’, calculate: function(data) { return data.first + ‘ ‘ + data.last’; } } [/js]

この指定方法だと、依存するフィールドの判定をフレームワークが行ってくれます。 こちらの方が簡単ですね。

バリデーション

Ext JS 4.x でのバリデーションは、モデルの valudations 配列に指定していました。

[js] Ext.define(‘User’, { extend: ‘Ext.data.Model’, config: { fields: [ {name: ‘name’, type: ‘string’}, {name: ‘age’, type: ‘int’}, {name: ‘phone’, type: ‘string’}, {name: ‘gender’, type: ‘string’}, {name: ‘username’, type: ‘string’}, {name: ‘alive’, type: ‘boolean’, defaultValue: true} ], validations: [ {type: ‘presence’, field: ‘age’}, {type: ‘length’, field: ‘name’, min: 2}, {type: ‘inclusion’, field: ‘gender’, list: [‘Male’, ‘Female’]}, {type: ‘exclusion’, field: ‘username’, list: [‘Admin’, ‘Operator’]}, {type: ‘format’, field: ‘username’, matcher: /([a-z]+)[0-9]{2,3}/} ] } }); var instance = Ext.create(‘User’, { name: ‘Ed’, gender: ‘Male’, username: ‘edspencer’ }); var errors = instance.validate(); console.log(errors); [/js]

Ext JS 5 では、validators コンフィグに指定します。 そして、validators は、モデルにも指定できますが、フィールドにも指定できます。

[js] // モデルに指定する validators: { age: { type: ‘presence’ }, username: [{ type: ‘exclusion’, list: [‘Admin’, ‘Operator’] }, { type: ‘format’, matcher: /([a-z]+)[0-9]{2,3}/ }] } [/js]

このように、すっきりと記述できます。 でももっといいのは、fields コンフィグの中に指定する方法です。

[js] fields: [{ name: ‘name’, validators: [{ type: ‘exclusion’, list: [‘root’, ‘admin’], message: ‘不正な名前’ }] }, { name: ‘weight’, validators: [{ type: ‘range’, min: 1, max: 300, message: ‘weight は 1 から 300 でなければなりません’ }, { type: ‘presence’, message: ‘weight を指定する必要があります’ }] }] [/js]

フィールドの定義としてまとめて定義できます。 よりすっきりしますね。

実は、単にすっきりするだけでなく、このことによりとても便利になる事があります。

カスタムフィールド

Ext JS 4.x でのフィールドは、Ext.data.Field クラスです。 フィールドのタイプは、そのクラスの一つのプロパティでした。 ですから、

[js] Ext.define(‘SomeModel’, { extend: ‘Ext.data.Model’, fields: [ {name: ‘user_name’, type: ‘string’}, {name: ‘age’, type: ‘int’}, {name: ‘birthday’, type: ‘date’} ] }) [/js]

こうした定義がある場合、3つのフィールドは、それぞれ Ext.data.Field クラスのインスタンスであり、type はそのプロパティになります。

Ext JS 5 では、上記の定義では、3つのフィールドはそれぞれ、Ext.data.field.StringExt.data.field.IntegerExt.data.field.Date というクラスのインスタンスになります。

これで何が嬉しいかというと、カスタムフィールドのクラスを定義して、使い回しができるようになるところです。

Sencha Touch や Ext JS 4 で、モデルでバリデーションのコードを書いていた方ならわかると思うのですが、そこかしこで同じようなバリデーションコードを書くことがありました。VTypes にカスタムのバリデーションを登録できるとはいうものの、バンドルされたバリデーション、例えば inclusion/exclusion などでリスト指定するような場合、そのリストは各モデルで定義しなければなりませんでした。 また、同じような convert メソッドをあちこちのモデル定義に書いた経験もあるでしょう。

カスタムフィールドクラスを定義できるようになったことで、それらのコードの重複を避ける事ができるようになりました。 カスタムフィールドの定義の中に、convertcaluculatevalidators を設定する事で、そのフィールドを使い回すことができるようになります。

性別のバリデーションを設定するために、顧客モデルにも、従業員モデルにも、同じ include の設定をする必要は無くなりました。性別を表すカスタムフィールドを作り、それを顧客モデル、従業員モデルで共有すれば良いのです。

[js] Ext.define(‘App.fields.Gender’, { extend: ‘Ext.data.field.String’, alias: ‘data.field.gender’, validators: { type: ‘inclusion’, list: [ ‘男’, ‘女’ ] } }); [/js]

このカスタムフィールドをモデルで使うには、type: 'gender' とするだけです。

チェーンドストア

Sencha のフレームワークでは、データパッケージとビューをバインドして、ストア (Ext.data.Store) の中にあるデータを、様々な形 (グリッド/データビュー/チャートなど) で表示できます。 ストアには、ソートやフィルタの機能がついていて、グリッドなどで簡単にフィルタリングやソーティングができます。 とても便利ですよね。

Ext JS 5 には、そのストアに、チェーンドストアというものが加わりました。

このチェーンドストアってなんでしょうか。 これは、データの実体を持たないストアのことです。 データの実体は、他のストアを参照します。

チェーンドストアでは、データの実体は持ちませんが、フィルタやソートの機能を、ソースのストアとは別に定義することができます。

これまで、一つのデータソースを違う観点 (フィルタ条件) で表示する必要がある場合は、2つのストアを用意する必要がありました。当然、メモリ内に配置されるデータもそれぞれで持つことになります。 チェーンドストアを使えば、データはソースのストアが持ち、チェーンドストアに違うフィルタをセットすることで、同じデータを違う観点で参照できます。

チェーンドストアを使う最も簡単な方法は、ViewModel の sotres で定義することです。

[js] stores: { users: { model: ‘MyApp.model.User’ }, femailusers: { source: ‘users’, filters: [{ property: ‘gender’, value: ‘femail’ }] } source: ‘Users’, } [/js]

stores コンフィグの中に source コンフィグを追加するだけで、そのストアはチェーンドストアになります。

明日は @kotsutsumi さんです。

それでは、みなさま良いお年を。