Ext JS 4のMVC Application Architectureを試してみた
先日ついにリリースされたExt JS 4に新たに追加されたMVCアーキテクチャを試してみました。
MVC Application Architecture
調べたことの簡単なまとめ
Ext JS 4のMVCアーキテクチャ
- モデル → Ext.data.Modelクラスを継承したクラス
- ビュー → パネル、グリッド、ツリーなどのコンポーネント
- コントローラー → Ext.app.Controllerクラスを継承したクラス
アプリケーションのディレクトリ構造
- appname - app - controller - model - store - view - resources - css - images - ... - app.js - index.html
appnameはアプリケーションの名前のディレクトリです。
アプリケーションはindex.htmlからロードするapp.jsで起動します。
このディレクトリ構造に沿うことで動的なJSファイルのロードや記述の簡略化などのフレームワークの恩恵を受けることができます。
index.html
<html> <head> <title>Contacts</title> <link rel="stylesheet" type="text/css" href="../ext-4.0.0/resources/css/ext-all.css" /> <link rel="stylesheet" type="text/css" href="resources/css/app.css" /> <script type="text/javascript" src="../ext-4.0.0/ext-debug.js"></script> <script type="text/javascript" src="app.js"></script> </head> <body></body> </html>
index.htmlからロードするのは
だけです。
その他のファイルはフレームワークがロードしてくれます。
app.js
Ext.application({ name: 'Contacts', appFolder: 'app', controllers: [ 'Contacts' ], launch: function() { Ext.create('Ext.container.Viewport', { layout: 'card', items: [ { xtype: 'contactlist' }, { xtype: 'contactnew' }, { xtype: 'contactedit' } ] }); } });
app.jsには
- nameにアプリケーションの名前を定義します。
- appFolderにアプリケーションの格納フォルダ(デフォルト:app)を指定します。
- controllerにアプリケーションのコントローラー(複数可)を指定します。
- launchに起動ファンクションを定義します。
Controller
Ext.define('Contacts.controller.Contacts', { extend: 'Ext.app.Controller', requires: [ 'Ext.layout.container.Card', 'Ext.layout.container.Border', 'Ext.data.proxy.Rest', 'Ext.form.field.Hidden' ], views: [ 'contact.List', 'contact.Grid', 'contact.New', 'contact.Edit', 'contact.Form' ], stores: [ 'Contacts' ], models: [ 'Contact' ], init: function() { console.log('controller init'); this.control({ 'contactgrid > toolbar > button[action=new]': { click: function(button) { button.up('viewport').getLayout().setActiveItem(1); } }, //snip }) } })
Controllerに定義することはモリモリあります。
- requiresで必要なレイアウトなどを指定します(これはいいのか不明)。
- viewsでアプリのビューを指定します。
- storesでアプリで使うStoreを指定します。
- modelsでアプリのモデルを指定します。
- initファンクションはアプリの起動前に呼び出されます。
- controlファンクションにはビューで発生するイベントのリスナーを定義できます。
イベントが発生するコンポーネントは
'contactgrid > toolbar > button[action=new]'
です。
CSSセレクタ風にExt JSのコンポーネントを指定できます。
このコンポーネントのclickイベントをリスンしています。
View
Ext.define('Contacts.view.contact.List', { extend: 'Ext.Panel', alias: 'widget.contactlist', layout: 'border', defaults: { border: false }, initComponent: function() { var me = this; Ext.apply(me, { items: [{ region: 'north', height: 50 }, { region: 'west', width: 200 }, { region: 'south', height: 200 }, { region: 'center', items: [ {xtype: 'contactgrid'} ] }] }); this.callParent(arguments); } });
ViewはExt JSのコンポーネントです。
基本的にExt JS3のときと同じように書けます。
明らかに変わったのは、xtypeの定義とinitComponentファンクションからのスーパークラスをコールするファンクションでしょうか。
xtypeは下記のように定義します。
alias: 'widget.contactlist',
widgetは必須のprefixです。他からこのコンポーネントをxtypeで指定するときは
xtype: 'contactlist'
になります。
スーパークラスをコールするファンクションはcallParentファンクションに変わっています。
ModelとStore
Ext.define('Contacts.model.Contact', { extend: 'Ext.data.Model', fields: [ "_docId", "givenName", "familyName", "emails", "phoneNumbers", ], proxy: { type: 'rest', url: '/_je/myDoc' } });
Modelはproxyを持ってサーバー通信したり、他のモデルとhas_manyなどの関連をもったり、バリデーションの機能があったりするようですが未検証です。
Ext.define('Contacts.store.Contacts', { extend: 'Ext.data.Store', model: 'Contact', fields: [ "_docId", "givenName", "familyName", "emails", "phoneNumbers", ], proxy: { type: 'rest', url: '/_je/myDoc' }, autoLoad: true });
StoreはModelの集約として使えます。Ext JS3からかなり変わったみたいですが未検証。