標籤:extjs4 javascript proxy data
周邦濤(Timen)
Email:[email protected]
轉載請註明出處: http://blog.csdn.net/zhoubangtao/article/details/27707361
1. 簡介
資料包主要負責載入和儲存你應用程式的所有資料,它包含41個類,但是其中三個是最重要的—— Model,Store和Ext.data.proxy.Proxy。這三個類幾乎在每個應用程式都有使用,並且有很多衛星類作支援。
2. Model和Store
data包的核心是Ext.data.Model。一個Model代表了一些資料的類型 —— 例如一個電子商務可能Users,Products和Orders模型。最簡單的說,一個Model就是一個欄位和資料的集合。現在來看看一個Model類的4個主要部分 —— Field,Proxy,Association和Validation。
讓我們看看怎麼建立一個Model:
Ext.define('User', { extend: 'Ext.data.Model', fields: [ { name: 'id', type: 'int' }, { name: 'name', type: 'string' } ]});
Model通常和Store一起使用,Store就是Model執行個體的集合。建立一個Store並且載入它的資料很簡單:
Ext.create('Ext.data.Store', { model: 'User', proxy: { type: 'ajax', url : 'users.json', reader: 'json' }, autoLoad: true});
我們來給我們的Store配置一個Ajax Proxy,告訴它載入資料url以及解析資料的Reader。這個例子中,我們的伺服器返回的是JSON,所以我們需要設定一個Json Reader去讀取回複。Store自動從users.json。users.json url應該返回一個像下邊的JSON字串:
{ success: true, users: [ { id: 1, name: 'Ed' }, { id: 2, name: 'Tommy' } ]}3 內部資料
Store也可以從內部載入資料。在內部,Store將每一個傳過去的對象轉換成Model執行個體:
Ext.create('Ext.data.Store', { model: 'User', data: [ { firstName: 'Ed', lastName: 'Spencer' }, { firstName: 'Tommy', lastName: 'Maintz' }, { firstName: 'Aaron', lastName: 'Conran' }, { firstName: 'Jamie', lastName: 'Avins' } ]});4. 排序和分組
Store可以執行排序、過濾和本地分組,以及支援遠程排序、過濾和分組:
Ext.create('Ext.data.Store', { model: 'User', sorters: ['name', 'id'], filters: { property: 'name', value : 'Ed' }, groupField: 'age', groupDir: 'DESC'});
在我們剛剛建立的Store中,資料會先以name,然後以id排序;並且被過濾到只剩下name包含‘Ed’的使用者,並且資料會以age做降序分組。可以通過Store的API在任意時間方便的改變排序、過濾和分組。
5. 代理(Proxy)
Store採用Proxy控制Model資料的載入和儲存。有兩種類型的Proxy:Client和Server。Client的例子是儲存資料到瀏覽器記憶體的Memory Proxy和使用HTML5本機存放區特性的Local Storage Proxy。Server Proxy處理遠程服務的資料解碼,它的例子有Ajax Proxy,JsonP Proxy以及Rest Proxy。
Proxy可以直接定義在一個Model中,例如:
Ext.define('User', { extend: 'Ext.data.Model', fields: ['id', 'name', 'age', 'gender'], proxy: { type: 'rest', url : 'data/users', reader: { type: 'json', root: 'users' } }});// Uses the User Model's ProxyExt.create('Ext.data.Store', { model: 'User'});
這有兩點好處。第一,每一個使用User Model的Store將會以同樣的方式載入它所需要的資料,所以避免了為每一個Store重複定義Proxy。第二,我們能夠不通過Store載入和儲存Model資料。
data without a Store:// Gives us a reference to the User classvar User = Ext.ModelMgr.getModel('User');var ed = Ext.create('User', { name: 'Ed Spencer', age : 25});// We can save Ed directly without having to add him to a Store first because we// configured a RestProxy this will automatically send a POST request to the url /usersed.save({ success: function(ed) { console.log("Saved Ed! His ID is "+ ed.getId()); }});// Load User 1 and do something with it (performs a GET request to /users/1)User.load(1, { success: function(user) { console.log("Loaded user 1: " + user.get('name')); }});
還有一些使用HTML5新特性的Proxy —— LocalStorage和SessionStorage。儘管較早的瀏覽器並不支援這些新的HTML5 API,它們是如此的有用,一大部分應用程式將會因它們的存在而受益。
6. 關聯
Model能夠採用Associations API關聯在一起。大多說應用程式處理各種各樣的Model,並且這些Model還總是相關聯。一個部落格應用可能有User、Post和Comment Model。每一個User建立多個Post,每個Post又接受多個Comment。看看我們是怎麼用Association來寫它們的模型的。
Ext.define('User', { extend: 'Ext.data.Model', fields: ['id', 'name'], proxy: { type: 'rest', url : 'data/users', reader: { type: 'json', root: 'users' } }, hasMany: 'Post' // shorthand for { model: 'Post', name: 'posts' }});Ext.define('Post', { extend: 'Ext.data.Model', fields: ['id', 'user_id', 'title', 'body'], proxy: { type: 'rest', url : 'data/posts', reader: { type: 'json', root: 'posts' } }, belongsTo: 'User', hasMany: { model: 'Comment', name: 'comments' }});Ext.define('Comment', { extend: 'Ext.data.Model', fields: ['id', 'post_id', 'name', 'message'], belongsTo: 'Post'});
在你的應用中表述不同Model之間的關係很輕鬆。每一個Model可以包含和其他Model的任意數量的關聯關係,並且你的Model可以以任意順序定義。一旦我們有了一個Model執行個體,我們就可以通過它訪問它關聯的資料 —— 例如,如果想把一個給定使用者的所有Post的所有Comment列印成日誌,我們可以這麼做:
// Loads User with ID 1 and related posts and comments using User's ProxyUser.load(1, { success: function(user) { console.log("User: " + user.get('name')); user.posts().each(function(post) { console.log("Comments for post: " + post.get('title')); post.comments().each(function(comment) { console.log(comment.get('message')); }); }); }});
上面我們建立的每一個hasMany關聯都會產生一個新函數並加入到這個Model中。我們定義每個User 模型 hasMany Post,這就在User Model中添加一個posts()方法。調用user.posts()會返回一個配置了Post Model的Store。相應的,Post Model會有一個comments()方法,因為我們給它配置了hasMany Comment。
Association不只有助於載入資料,它還有助於建立新紀錄:
user.posts().add({ title: 'Ext JS 4.0 MVC Architecture', body: 'It\'s a great Idea to structure your Ext JS Applications using the built in MVC Architecture...'});user.posts().sync();
這裡我們執行個體化一個Post,它的user_id欄位會被自動府城User的id。調用sync()會通過配置給它的Proxy儲存這個新的Post —— 這還是一個非同步作業,如果你想當這個操作完成時受到通知,你可以給它傳入一個Callback函數。
belongsTo關聯也會在Model上產生新方法,看看我們怎麼使用:
// get the user reference from the post's belongsTo associationpost.getUser(function(user) { console.log('Just got the user reference from the post: ' + user.get('name'))});// try to change the post's userpost.setUser(100, { callback: function(product, operation) { if (operation.wasSuccessful()) { console.log('Post\'s user was updated'); } else { console.log('Post\'s user could not be updated'); } }});
這裡的載入函數(也就是getUser)也是非同步,你也可一個傳入一個Callback函數。setUser方法簡單地更新外鍵(foreign_key,也就這裡的user_id)為100,然後儲存Post模型,同樣,穿進去的Callback函數將會在儲存操作完成(無論成功或失敗)時被觸發。
7. 載入嵌套資料
你可能會質疑,為什麼我們給User.load傳入一個success函數,但是當我們訪問User的post和comment時卻不必如此?!那是因為上邊的例子我們假設當發起一個擷取User的請求時,伺服器返回了User資料以及它說關聯的Post和Comment資料。通過上邊的關聯設定,架構會自動解析單個請求中的嵌套資料。為避免為一個User資料發一個請求,然後請求他的所有的Post資料,之後在為每一個Post載入器Comment資料,我們可以直接讓伺服器返回以上所有的資料:
{ success: true, users: [ { id: 1, name: 'Ed', age: 25, gender: 'male', posts: [ { id : 12, title: 'All about data in Ext JS 4', body : 'One areas that has seen the most improvement...', comments: [ { id: 123, name: 'S Jobs', message: 'One more thing' } ] } ] } ]}8. 驗證
對資料的驗證使得Ext JS 4 的模型更加豐富。為了證明,我們基於上邊講解關聯的例子做進一步改進。首先向User模型添加一些驗證:
Ext.define('User', { extend: 'Ext.data.Model', fields: ..., validations: [ {type: 'presence', name: 'name'}, {type: 'length', name: 'name', min: 5}, {type: 'format', name: 'age', matcher: /\d+/}, {type: 'inclusion', name: 'gender', list: ['male', 'female']}, {type: 'exclusion', name: 'name', list: ['admin']} ], proxy: ...});
驗證的格式定義和欄位的相同。在上邊的每個例子中,我們為驗證指定一個欄位和類型。上邊例子中的驗證意思是name欄位必須存在,且至少有5個字元,age欄位是個數字,gender欄位要麼是“male”,要麼是“female”,username可以是除了“admin”之外的任何值。一些驗證還需要其他的額外配置,例如length驗證需要min和max屬性,format驗證需要matcher,等等。Ext JS 4 有5種內建的驗證方式,並且添加定製化的驗證規則也很簡單。下邊看一下這些內建的驗證方式:
- presence: 確保欄位有值。零算作有效值,但是Null 字元串不算
- length: 確保字串長度在min和max之間。這兩個都是可選的。
- format: 確保一個字串匹配一個Regex。上邊的例子意思是確保一個欄位是由4個數字後跟至少一個字元組成。
- inclusion: 確保一個值位於一個指定的集合中(例如,確保性別是male或者female)
- exclusion: 確保一個值不在一個指定的集合中(例如黑名單使用者名稱,像’admin‘)
現在我們對不能的驗證做什麼事情有一個瞭解了,讓我們在一個User執行個體上使用一下。首先建立一個user,然後運行驗證方法,注意出現的錯誤:
// now lets try to create a new user with as many validation errors as we canvar newUser = Ext.create('User', { name: 'admin', age: 'twenty-nine', gender: 'not a valid gender'});// run some validation on the new user we just createdvar errors = newUser.validate();console.log('Is User valid?', errors.isValid()); //returns 'false' as there were validation errorsconsole.log('All Errors:', errors.items); //returns the array of all errors found on this model instanceconsole.log('Age Errors:', errors.getByField('age')); //returns the errors for the age field
這裡的關鍵函數式validate(),它運行所有配置的驗證,然後返回一個Errors對象。Errors對象包含任何發現的錯誤的集合,再加上一些方便的方法,例如isValid(),如果在任何欄位上都沒有錯誤,它會返回true,以及getByField()方法,它會返回一個給定欄位上出現的所有錯誤。
9. 總結
本章主要講述了Ext JS 4的Data包中的主要功能,從Model、Store、Proxy以及Model的關聯以及驗證等方面做了詳細介紹。通過本文的學習,你能都Ext JS 4的資料操作和互動有一個初步的認識。
10. 參考資料
- http://dev.sencha.com/deploy/ext-4.1.0-gpl/docs/index.html#!/guide/data
周邦濤(Timen)
Email:[email protected]
轉載請註明出處: http://blog.csdn.net/zhoubangtao/article/details/27707361