The data package is what loads and saves all of the data in your application and consists of 41 classes, but there are three that are more important than all the others - Model, Store and Ext.data.proxy.Proxy. These are used by almost every application, and are supported by a number of satellite classes:html
數據包加載並保存您的應用程序中的全部數據。它包括41類,但其中有三個,比其餘的都重要 - Model, Store 和 Ext.data.proxy.Proxy。這些幾乎每個應用程序都會用到。這三個類還有些支持的衛星類:ajax
The centerpiece of the data package is Ext.data.Model. A Model represents some type of data in an application - for example an e-commerce app might have models for Users, Products and Orders. At its simplest a Model is just a set of fields and their data. We’re going to look at four of the principal parts of Model — Fields, Proxies, Associations and Validations.正則表達式
數據包的核心是Ext.data.Model。 Model表明應用程序中的一些類型數據 - 例如一個電子商務應用程序可能會有Users, Products 和 Orders模型。最簡單的一個模型僅僅是一個字段和他們的數據。咱們要看看模型的四個主要部分— Fields, Proxies, Associations 和Validations 。express
Let's look at how we create a model now:讓咱們看看怎麼建立一個Model:json
Ext.define('User', { extend: 'Ext.data.Model', fields: [ { name: 'id', type: 'int' }, { name: 'name', type: 'string' } ] });
Models are typically used with a Store, which is basically a collection of Model instances. Setting up a Store and loading its data is simple:api
Models一般會用到Store,Store基本上是Models實例的一個集合。創建一個Store和加載其數據很簡單:瀏覽器
Ext.create('Ext.data.Store', { model: 'User', proxy: { type: 'ajax', url : 'users.json', reader: 'json' }, autoLoad: true });
We configured our Store to use an Ajax Proxy, telling it the url to load data from and the Reader used to decode the data. In this case our server is returning JSON, so we've set up a Json Reader to read the response. The store auto-loads a set of User model instances from the url users.json
. Theusers.json
url should return a JSON string that looks something like this:服務器
咱們配置Store使用Ajax Proxy,告訴它加載數據的URL,並用一個Reader解析數據。在這種狀況下,咱們的服務器返回JSON,因此咱們建立一個JSON Reader來讀取響應。Store從URL users.json中自動加載User model實例集合。 users.json URL應該返回一個JSON字符串,看起來像這樣:app
{ success: true, users: [ { id: 1, name: 'Ed' }, { id: 2, name: 'Tommy' } ] }
For a live demo please see the Simple Store example.框架
Simple Store例子裏有現場演示。
Stores can also load data inline. Internally, Store converts each of the objects we pass in as data into Model instances:
Store也能夠載入內聯的數據。在內部,Store轉換每一個做爲data (數據)傳遞到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' } ] });
Stores are able to perform sorting, filtering and grouping locally, as well as supporting remote sorting, filtering and grouping:
Stores可以執行本地排序、過濾和分組,以及支持遠程排序,過濾和分組:
Ext.create('Ext.data.Store', { model: 'User', sorters: ['name', 'id'], filters: { property: 'name', value : 'Ed' }, groupField: 'age', groupDir: 'DESC' });
In the store we just created, the data will be sorted first by name then id; it will be filtered to only include Users with the name 'Ed' and the data will be grouped by age in descending order. It's easy to change the sorting, filtering and grouping at any time through the Store API. For a live demo, see theSorting Grouping Filtering Store example.
在咱們剛剛建立的Store中,數據將首先由名稱,而後由ID進行排序,它會過濾爲只包括name爲「Ed」的數據,而且數據按照年齡分組降序排列。經過Store API很容易在任什麼時候間改變排序,過濾和分組。現場演示,請參閱 Sorting Grouping Filtering Store例子。
Proxies are used by Stores to handle the loading and saving of Model data. There are two types of Proxy: Client and Server. Examples of client proxies include Memory for storing data in the browser's memory and Local Storage which uses the HTML 5 local storage feature when available. Server proxies handle the marshaling of data to some remote server and examples include Ajax, JsonP and Rest.
代理用於Store,處理載入和保存模型數據。有兩種類型的代理:客戶端和服務器端。客戶端代理的例子包括在瀏覽器的內存和HTML 5的本地存儲功能可用時。服務器端代理封裝處理一些遠程服務器數據,其中包括Ajax,Json和Rest。
Proxies can be defined directly on a Model like so:
代理能夠在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 Proxy Ext.create('Ext.data.Store', { model: 'User' });
This helps us in two ways. First, it's likely that every Store that uses the User model will need to load its data the same way, so we avoid having to duplicate the Proxy definition for each Store. Second, we can now load and save Model data without a Store:
這在兩個方面有助於咱們。首先,極可能每一個使用User model的Stroe都須要以一樣的方式加載數據,這樣就使咱們避免重複定義每一個Stroe的Proxy。第二,咱們如今不須要Store就能夠載入和保存模型Model:
// Gives us a reference to the User class 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 // configured a RestProxy this will automatically send a POST request to the url /users 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.load(1, { success: function(user) { console.log("Loaded user 1: " + user.get('name')); } });
There are also Proxies that take advantage of the new capabilities of HTML5 - LocalStorage and SessionStorage. Although older browsers don't support these new HTML5 APIs, they're so useful that a lot of applications will benefit enormously from their presence.
也有利用HTML5新功能優點的代理, -LocalStorage 和SessionStorage。雖然舊的瀏覽器不支持HTML5的這些新API,可是這個技術前景極好。
Example of a Model that uses a Proxy directly
Models can be linked together with the Associations API. Most applications deal with many different Models, and the Models are almost always related. A blog authoring application might have models for User, Post and Comment. Each User creates Posts and each Post receives Comments. We can express those relationships like so:
Models能夠用Associations API聯繫在一塊兒。大多數應用程序處理許多不一樣的Models,Models幾乎都是相關的。一個博客應用程序可能有User,Post和CommentModel。用戶能夠建立文章,文章能夠收到評論。咱們能夠像這樣表達這些關係:
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' });
It's easy to express rich relationships between different Models in your application. Each Model can have any number of associations with other Models and your Models can be defined in any order. Once we have a Model instance we can easily traverse the associated data - for example, if we wanted to log all Comments made on each Post for a given User, we can do something like this:
能夠很容易地表達您的應用程序中的不一樣Models之間的豐富關係。每一個模型能夠有任意數量的Associations與其餘Models關聯,Models能夠按照任何的順序定義。一旦咱們有一個Models的實例,咱們能夠很容易地遍歷相關的數據 - 例如,若是咱們想記錄每一個文章上給定用戶的全部評論,咱們能夠這樣作:
// Loads User with ID 1 and related posts and comments using User's Proxy 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')); }); }); } });
Each of the hasMany associations we created above results in a new function being added to the Model. We declared that each User model hasMany Posts, which added the user.posts()
function we used in the snippet above. Calling user.posts()
returns a Store configured with the Post model. In turn, the Post model gets a comments()
function because of the hasMany Comments association we set up.
在咱們上面建立的每個hasMany關聯的結果都會產生一個新的函數添加到Model中。咱們定義User model hasMany Posts,會新增user.posts()函數供咱們在上面的代碼片斷使用。調用guser.posts()返回Post model的 Store配置。反過來,Post model獲取comments() 函數是由於咱們設置的Comments的hasMany關聯。
Associations aren't just helpful for loading data - they're useful for creating new records too:
關聯不只僅用於加載數據 – 建立新紀錄的時候也很是有用:
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();
Here we instantiate a new Post, which is automatically given the User's id in the user_id field. Calling sync() saves the new Post via its configured Proxy - this, again, is an asynchronous operation to which you can pass a callback if you want to be notified when the operation completed.
在這裏,咱們實例化一個新的Post(文章),user_id字段會自動填充上用戶ID。調用sync()經過其配置的Proxy保存新Post - 這又是一個異步操做。若是你想操做完成時發送通知,也能夠添加一個回調(callback)。
The belongsTo association also generates new methods on the model, here's how we can use those:
belongsTo關聯也能夠生成新的Model方法,能夠這樣使用這些方法:
// get the user reference from the post's belongsTo association post.getUser(function(user) { console.log('Just got the user reference from the post: ' + user.get('name')) }); // try to change the post's 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'); } } });
Once more, the loading function (getUser) is asynchronous and requires a callback function to get at the user instance. The setUser method simply updates the foreign_key (user_id in this case) to 100 and saves the Post model. As usual, callbacks can be passed in that will be triggered when the save operation has completed - whether successful or not.
再次,加載函數(getUser)是異步的,須要一個回調函數來獲取用戶實例。setUser方法只需更新foreign_key(這裏是user_id)爲100並保存Post model。像往常同樣,能夠在已完成保存操做時觸發回調- 不管成功與否。
You may be wondering why we passed a success
function to the User.load call but didn't have to do so when accessing the User's posts and comments. This is because the above example assumes that when we make a request to get a user the server returns the user data in addition to all of its nested Posts and Comments. By setting up associations as we did above, the framework can automatically parse out nested data in a single request. Instead of making a request for the User data, another for the Posts data and then yet more requests to load the Comments for each Post, we can return all of the data in a single server response like this:
你也許會奇怪,爲何咱們發送一個成功函數到User.load的調用,但在訪問用戶的文章和評論時卻沒有這樣作。這是由於上面的例子中假定,當咱們提出請求獲取一個用戶,服務器返回的用戶數據會嵌套全部的文章和評論。經過設立象咱們上面那樣的關聯,框架能夠自動解析出嵌套在單一請求中的數據。框架不是先獲取用戶數據,而後調用另外一個請求獲取文章數據,而後再發出更多的請求獲取評論,而是在一個服務器響應裏返回全部數據:
{ 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' } ] } ] } ] }
The data is all parsed out automatically by the framework. It's easy to configure your Models' Proxies to load data from almost anywhere, and their Readers to handle almost any response format. As with Ext JS 3, Models and Stores are used throughout the framework by many of the components such a Grids, Trees and Forms.
數據所有是框架自動分析的。能夠很容易地配置Model的代理加載任何地方的數據,用他們的Reader來處理幾乎任何返回的格式。至於Ext JS3,整個框架的許多組件都用到了Model和Store,如Grids, Trees and Forms。
See the Associations and Validations demo for a working example of models that use relationships.
Associations and Validations 演示了Model的使用。
Of course, it's possible to load your data in a non-nested fashion. This can be useful if you need to "lazy load" the relational data only when it's needed. Let's just load the User data like before, except we'll assume the response only includes the User data without any associated Posts. Then we'll add a call to user.posts().load()
in our callback to get the related Post data:
固然,它能夠用非嵌套的方式來加載數據。若是你須要「懶加載(只有被須要的時候纔會加載)」,這就會有用了。咱們只是像之前那樣加載User數據,但咱們假設響應只包含User數據而沒有任何關聯的Post。而後,咱們將在回調中添加一個調用user.posts().load()的方法,以得到相關的Post數據。
// 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 Proxy user.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')); }); }); } }); } });
For a full example see Lazy Associations
As of Ext JS 4 Models became a lot richer with support for validating their data. To demonstrate this we're going to build upon the example we used above for associations. First let's add some validations to the User
model:
Ext JS4Model的數據驗證變得更豐富了不少。爲了證實這一點,咱們要用上述關聯的例子。首先,讓咱們添加一些驗證的User model:
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: ... });
Validations follow the same format as field definitions. In each case, we specify a field and a type of validation. The validations in our example are expecting the name field to be present and to be at least 5 characters in length, the age field to be a number, the gender field to be either "male" or "female", and the username to be anything but "admin". Some validations take additional optional configuration - for example the length validation can take min and max properties, format can take a matcher, etc. There are five validations built into Ext JS and adding custom rules is easy. First, let's meet the ones built right in:
驗證字段定義遵循相同的格式。在每一種狀況下,咱們指定一個字段和驗證的類型。但願在咱們的例子驗證name字段必須存在至少5個字符長度,age字段是一個數字,gender(性別)字段要麼是「male」要麼是「female」,username能夠是除了「admin」的任何東西。一些驗證採起額外的可選配置 - 例如長度驗證能夠採起Min和Max屬性,格式能夠用正則表達式等等。有五個Ext JS的內置驗證,添加自定義的規則也很容易。首先,讓咱們看看內置驗證:
presence
simply ensures that the field has a value. Zero counts as a valid value but empty strings do not.確保該字段有一個值。計數0有效,可是空字符串無效。length
ensures that a string is between a min and max length. Both constraints are optional.確保一個字符串在最小和最大長度之間。這兩種約束是可選的. format
ensures that a string matches a regular expression format. In the example above we ensure that the age field consists only of numbers.確保一個字符串匹配一個正則表達式格式。在上面的例子中,咱們必須確保年齡字段是由至少一個字母后面跟4個數字組成(譯者:這裏可能有錯誤?)。inclusion
ensures that a value is within a specific set of values (e.g. ensuring gender is either male or female).確保值是特定的值(例如確保性別是男性或女性)。exclusion
ensures that a value is not one of the specific set of values (e.g. blacklisting usernames like 'admin').確保不是某值(例如列入黑名單的username,像是「admin」)。Now that we have a grasp of what the different validations do, let's try using them against a User instance. We'll create a user and run the validations against it, noting any failures:
如今,咱們已經掌握了不一樣的驗證都是作什麼的,讓咱們嘗試對用戶實例中使用它們。咱們將建立一個用戶,並針對它運行驗證,並指出任何錯誤:
// now lets try to create a new user with as many validation errors as we can 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 var errors = newUser.validate(); console.log('Is User valid?', errors.isValid()); //returns 'false' as there were validation errors console.log('All Errors:', errors.items); //returns the array of all errors found on this model instance console.log('Age Errors:', errors.getByField('age')); //returns the errors for the age field
The key function here is validate(), which runs all of the configured validations and returns an Errors object. This simple object is just a collection of any errors that were found, plus some convenience methods such as isValid()
- which returns true if there were no errors on any field - andgetByField()
, which returns all errors for a given field.
這裏的主要是validate()方法,它運行全部配置的驗證,並返回一個錯誤對象。這個簡單的對象只是一個任何被發現的錯誤的集合。還有一些方便的方法,好比isValid(),若是任何字段都沒有錯誤就返回true。 getByField(),它返回一個給定字段中的全部錯誤。
For a complete example that uses validations please see Associations and Validations
這裏的主要是validate()方法,它運行全部配置的驗證,並返回一個錯誤對象。這個簡單的對象只是一個任何被發現的錯誤的集合。還有一些方便的方法,好比isValid(),若是任何字段都沒有錯誤就返回true。 getByField(),它返回一個給定字段中的全部錯誤。