javascript
ExtJS4 API文档阅读(四)——Data
2019獨角獸企業(yè)重金招聘Python工程師標準>>>
ExtJS4 API文檔閱讀(四)——Data
數(shù)據(jù)
Data包負責(zé)加載和保存你應(yīng)用程序中的所有數(shù)據(jù),由41個類構(gòu)成,其中有三個類是最重要的,分別是模型類(Model),存儲類(Store),代理類(Ext.data.proxy.Proxy)。它們幾乎在每個應(yīng)用程序中都被使用到,并且有很多相附類為它們提供支持。
模型類和存儲類
模型類(Ext.data.Model)是data包的核心部件。每個模型代表應(yīng)用程序中的一些數(shù)據(jù)類型-例如一個電子商務(wù)應(yīng)用程序可以有Users、Products、Orders等模型類。簡單來說,模型僅僅是一些域和每個域?qū)?yīng)數(shù)據(jù)的集合。我們將重點研究模型類中的四個主要部分—域(Fields)、代理(Proxies)、關(guān)聯(lián)(Associations)和驗證(Validations)。
現(xiàn)在讓我們看看如何創(chuàng)建一個模型類:
Ext.define('User', {extend: 'Ext.data.Model',fields: [{ name: 'id', type: 'int' },{ name: 'name', type: 'string' }] });
模型類通常在存儲類中使用,這些存儲類主要是一些模型實例的集合。設(shè)置存儲類和加載它的數(shù)據(jù)是很簡單的:
Ext.create('Ext.data.Store', {model: 'User',proxy: {type: 'ajax',url : 'users.json',reader: 'json'},autoLoad: true });
我們用Ajax代理(?Ajax Proxy)配置我們的存儲類,告訴它加載數(shù)據(jù)的url地址和用來解碼數(shù)據(jù)的讀取器(Reader)。這樣,我們的服務(wù)器將返回JSON格式的數(shù)據(jù),我們可以使用設(shè)置的Json讀取器(Json Reader)來解析響應(yīng)。上面創(chuàng)建的存儲類實例從url地址users.json中自動加載一系列User模型類實例的數(shù)據(jù)。
users.json應(yīng)該返回如下所示的JSON字符串:
{success: true,users: [{ id: 1, name: 'Ed' },{ id: 2, name: 'Tommy' }] }
請查看Simple Store獲取一個演示實例。
內(nèi)聯(lián)數(shù)據(jù)
存儲類實例也可以加載內(nèi)聯(lián)數(shù)據(jù),它們轉(zhuǎn)換每個傳遞進data中的對象為模型類實例:
Ext.create('Ext.data.Store', {model: 'User',data: [{ firstName: 'Ed', lastName: 'Spencer' },{ firstName: 'Tommy', lastName: 'Maintz' },{ firstName: 'Aaron', lastName: 'Conran' },{ firstName: 'Jamie', lastName: 'Avins' }] });
內(nèi)聯(lián)數(shù)據(jù)的例子(Inline Data example)
排序和分組
存儲類實例能在本地執(zhí)行排序、過濾和分組,同樣也提供遠程排序、過濾和分組:
Ext.create('Ext.data.Store', {model: 'User',sorters: ['name', 'id'],filters: {property: 'name',value : 'Ed'},groupField: 'age',groupDir: 'DESC' });
我們剛剛創(chuàng)建的存儲類實例中,數(shù)據(jù)首先將按照name排序,其次按id排序;并且數(shù)據(jù)將被過濾為僅包含name為’Ed’的Users,然后數(shù)據(jù)將按年齡進行分組且遵循由小到大的順序。任何時候調(diào)用存儲類的API進行排序、過濾和分組都是是很輕松的。查看排序、分組、過濾存儲類實例(Sorting Grouping Filtering Store)獲取一個演示示例。
代理
代理類被存儲類使用以便于管理加載和保存模型類數(shù)據(jù)。有兩種類型的代理:客戶端代理(Client)和服務(wù)器端代理(Server)。客戶端代理包括存儲數(shù)據(jù)在瀏覽器內(nèi)存的內(nèi)存方式(Memory)和使用HTML5本地存儲器(可用時)的本地存儲方式(Local Storage)。服務(wù)器端代理操作一些從遠程服務(wù)器調(diào)度來的數(shù)據(jù),例如包括Ajax,Jsonp和Rest方式。
代理方式可以直接在模型類中定義,如下:
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 Proxy Ext.create('Ext.data.Store', {model: 'User' });
這對我們有兩方面的好處:首先,使得每個使用User模型類的存儲類實例以相同方式加載數(shù)據(jù)變得可行,這樣我們避免了必須為每個存儲類實例復(fù)制相同代理方式的定義。其次,現(xiàn)在我們可以不必使用存儲類來加載和保存模型數(shù)據(jù):
// Gives us a reference to the User class // 創(chuàng)建一個User類的引用 var 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 //我們可以直接保存ed而不用先把它添加到一個存儲類中,因為我們配置了 // configured a RestProxy this will automatically send a POST request to the url /users //一個能自動發(fā)送一個POST請求到指定url的Rest代理 ed.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 1并對其一些相關(guān)操作(執(zhí)行一個GET請求到 /users/1) User.load(1, {success: function(user) {console.log("Loaded user 1: " + user.get('name'));} });
也有利用HTML5新功能--?LocalStorage和?SessionStorage?–?的代理模式。盡管舊的瀏覽器不支持這些新的HTML5 APIs,它們?nèi)匀皇怯杏玫?#xff0c;因為很多應(yīng)用程序?qū)倪@些新特性的存在中受益。
直接在模型類中使用代理的例子(Example of a Model that uses a Proxy directly)
關(guān)聯(lián)
模型類之間可以通過關(guān)聯(lián)API鏈接在一起。大多數(shù)應(yīng)用程序需要處理很多不同的模型類,并且這些模型類之間通常是相關(guān)聯(lián)的。例如一個博客寫作應(yīng)用程序可能有User(用戶)、Post(文章)、Comment(評論)等模型類。每個用戶(User)可以創(chuàng)建多篇文章(Posts),并且每篇文章接受很多評論(Comments)。我們可以如下表示這些關(guān)系:
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' });
這將使得在你的應(yīng)用程序中表示這種復(fù)雜關(guān)系變得簡單。?每個模型類可以和其他模型類有任意多的關(guān)聯(lián),并且你的模型類可以按任意順序定義。一旦我們創(chuàng)建了一個模型類實例,我們可以很輕松地遍歷與其相關(guān)聯(lián)的數(shù)據(jù)?--?例如,如果我們想記錄一個給定用戶的每篇文章的所有相關(guān)評論,我們可以如下這樣操作:
// Loads User with ID 1 and related posts and comments using User's Proxy //加載User使用ID 1和相關(guān)的文章和評論使用User的代理 User.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'));});});} });
上例我們創(chuàng)建每一個的hasMany關(guān)聯(lián)將產(chǎn)生一個新方法添加到這個模型類上。我們聲明的每個User模型類實例有許多(hasMany)文章(Posts),這將為我們添加user.posts()方法,如上面代碼段中使用的那樣。調(diào)用user.posts()方法將返回一個配置了Post模型的存儲類實例。依次類推,Post模型實例獲取了一個comments()方法,因為我們?yōu)槠湓O(shè)置了hasMany?評論關(guān)聯(lián)。關(guān)聯(lián)不僅對加載數(shù)據(jù)來說是有用的,而且對創(chuàng)建新記錄也是有用的:
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賦值給Post中的user_id字段。調(diào)用sync()方法,將通過配置的代理方式來保存新創(chuàng)建的Post模型類實例?–?再者,如果你想讓操作完成時得到反饋,你可以調(diào)用異步操作并傳遞進一個回調(diào)函數(shù)來實現(xiàn)。屬于(belongsTo)關(guān)聯(lián)也能在模型類實例中生成一個新方法,如我們下面介紹的這個示例:
// get the user reference from the post's belongsTo association //得到user實例引用從post實例的belongsTo關(guān)聯(lián)配置 post.getUser(function(user) {console.log('Just got the user reference from the post: ' + user.get('name')) }); // try to change the post's user //嘗試改變文章的user post.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');}} });
再次說明,加載函數(shù)(getUser)是異步調(diào)用的,并且需要一個回調(diào)函數(shù)作為參數(shù)來獲得user實例。setUser方法僅更新外鍵(本例中的user_id字段)的值為100,并保存這個Post模型類實例。通常,不管成功與否,當保存操作完成時,傳遞進去的回調(diào)函數(shù)都將被觸發(fā)。
加載內(nèi)嵌的數(shù)據(jù)
你或許想知道為什么調(diào)用User.load方法時,我們傳遞一個success方法,但當訪問User的文章(Post)及評論(Comment)時我們并不需要這樣做。這是因為上面的例子中,我們假定當發(fā)送請求以獲取一個用戶的信息時,服務(wù)器返回了該用戶的數(shù)據(jù)及所有嵌套的文章和評論的數(shù)據(jù)。上例我們通過設(shè)置關(guān)聯(lián)配置,框架在一次請求中就能自動解析出嵌套的數(shù)據(jù)。不是靠先發(fā)送一個請求獲取用戶數(shù)據(jù),另一個請求獲取文章數(shù)據(jù),再發(fā)送其他請求以獲取每篇文章的評論數(shù)據(jù)這種模式,我們可以在一次服務(wù)器響應(yīng)中返回所有的數(shù)據(jù),如下:
{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'}]}]}] }
這些數(shù)據(jù)將被框架自動解析出來。配置模型類的代理方式以用來加載任何地方的數(shù)據(jù)會變得很輕松,并且它們的閱讀器模式幾乎可以處理任何格式的響應(yīng)數(shù)據(jù)。和Ext JS 3一樣,模型類和存儲類在整個框架中被許多組件使用,例如表格,樹,表單。
查看關(guān)聯(lián)和驗證(Associations and Validations)的演示示例以獲取一個可實際操作并且具有關(guān)聯(lián)關(guān)系的模型實例。
當然,你可以以一種非嵌套的方式加載你的數(shù)據(jù)。如果你僅想需要時加載相關(guān)的數(shù)據(jù),這種“懶惰加載”模式將可能是有效地。如前所做,我們僅加載User數(shù)據(jù),除此之外,我們假定返回的響應(yīng)僅包含User數(shù)據(jù),沒有任何相關(guān)聯(lián)的文章(Post)數(shù)據(jù)。然后,我們在user.posts().load()方法添加回調(diào)函數(shù)中以獲取相關(guān)的文章(Post)數(shù)據(jù):
// Loads User with ID 1 User's Proxy User.load(1, {success: function(user) {console.log("User: " + user.get('name'));// Loads posts for user 1 using Post's Proxyuser.posts().load({callback: function(posts, operation) {Ext.each(posts, function(post) {console.log("Comments for post: " + post.get('title'));post.comments().each(function(comment) {console.log(comment.get('message'));});});}});} });
查看懶惰關(guān)聯(lián)(Lazy Associations)模式可以獲取一個完整的示例
驗證
自Ext JS 4起,模型類由于提供了驗證數(shù)據(jù)的功能而變得更加豐富精彩了。為了證明這點,我們將在前面使用過的關(guān)聯(lián)例子的基礎(chǔ)上構(gòu)建一個示例。首先讓我們添加一些驗證到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域必須為數(shù)字,gender域的值只能為male或female,并且用戶名可以為除了admin外的其他任何名稱。一些驗證器可能具有其他的可選配置?--?例如,長度驗證可以具有最大和最小屬性,格式(format)可以具有匹配(matcher)屬性等。Ext JS有五種內(nèi)置的驗證器,且可以輕松地添加用戶自定義規(guī)則。首先讓我們看看這五種類型:
- 存在(presence)??確保該域必須有確定值。0被看作有效值,但空字符串將不被視為有效值。
- 長度(length)??確保一個字符串長度位于最大和最小值之間。兩個參數(shù)都是可選的。
- 格式(format)??確保一個字符串匹配指定的正則表達式。上例中我們確保age域必須為數(shù)字。
- 包含(inclusion)?確保該域的值在指定的數(shù)值集合中(例如確保性別只能是男或女)。
- 排除(exclusion)?確保該域的值不在指定的數(shù)值集合中(例如用戶名不能為admin)
既然我們已經(jīng)理解了不同驗證器的功能,讓我們嘗試在一個User實例中使用它們。
我們創(chuàng)建一個user實例并在其中運行驗證器,注意產(chǎn)生的任何錯誤:
// now lets try to create a new user with as many validation errors as we can // 現(xiàn)在讓我們嘗試創(chuàng)建一個user實例,并產(chǎn)生盡量多的驗證錯誤 var newUser = Ext.create('User', {name: 'admin',age: 'twenty-nine',gender: 'not a valid gender' }); // run some validation on the new user we just created // 在我們剛剛創(chuàng)建的user實例中運行一些驗證器 var errors = newUser.validate(); console.log('Is User valid?', errors.isValid()); //returns 'false' as there were validation errors 當有驗證器錯誤產(chǎn)生時,返回false console.log('All Errors:', errors.items); //returns the array of all errors found on this model instance返回該模型類實例所有錯誤組合成的數(shù)組 console.log('Age Errors:', errors.getByField('age')); //returns the errors for the age field返回age域產(chǎn)生的錯誤
這里的關(guān)鍵函數(shù)是validate(),該函數(shù)運行所有配置驗證器并返回一個Errors對象。這個簡單的對象為所有錯誤的集合,并且添加了一些便利的方法,例如isValid()?--?當任何域都沒有錯誤產(chǎn)生時,返回true,還有g(shù)etByField()方法,返回給定域產(chǎn)生的所有錯誤。
請查看關(guān)聯(lián)和驗證(Associations and Validations)示例以獲取一個使用驗證器的復(fù)雜例子。
轉(zhuǎn)載于:https://my.oschina.net/yoyoko/blog/130966
總結(jié)
以上是生活随笔為你收集整理的ExtJS4 API文档阅读(四)——Data的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: TCPDUMP for Android(
- 下一篇: Linux安装SNMP