ExtJS 4 官方指南:数据 Data 简体中文版
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
ExtJS 4 官方指南翻译:数据Data 数据包加载并保存您的应用程序中的所有数据。
它包括41类,但其中有三个,比其他的都
, Store和
有些支持的卫星类:
1模型和存储Models and Stores
让我们看看怎么创建一个Model:
Ext.define('User',{
extend:'Ext.data.Model',
fields:[
{ name:'id', type:'int'},
{ name:'name', type:'string'}
]
});
Models通常会用到Store,Store基本上是Models实例的一个集合。
建立一个Store和加载其数据很简单:
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:
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 从URL users.json中自动加载User model实例集合。
users.json URL应该返回一个JSON 字符串,看起来像这样:
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. The users.json url should return a JSON string that looks something like this:
{
success:true,
users:[
{ id:1, name:'Ed'},
{ id:2, name:'Tommy'}
]
}
Simple Store例子里有现场演示。
For a live demo please see the Simple Store example.
2内联数据Inline data
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'}
]
});
Inline Data例子
Inline Data example
3排序和分组Sorting and Grouping
Stores能够执行本地排序、过滤和分组,以及支持远程排序,过滤和分组:
Stores are able to perform sorting, filtering and grouping locally, as well as supporting remote sorting, filtering and grouping:
Ext.create('Ext.data.Store',{
model:'User',
sorters:['name','id'],
filters:{
property:'name',
value :'Ed'
},
groupField:'age',
groupDir:'DESC'
});
在我们刚刚创建的Store中,数据将首先由名称,然后由ID进行排序,它会过滤为只包括name为“Ed”的数据,并且数据按照年龄分组降序排列。
通过Store API很容易在任何时间改变排序,过滤和分组。
现场演示,请参阅Sorting Grouping Filtering Store例子。
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 the Sorting Grouping Filtering Store example.
4代理Proxies
代理用于Store,处理载入和保存模型数据。
有两种类型的代理:客户端和服务器端。
客户端代理的例子包括在浏览器的内存和HTML 5的本地存储功能可用时。
服务器端代理封装处理一些远程服务器数据,其中包括Ajax,Json和Rest。
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, Json and Rest.
代理可以在Model中直接定义,像这样:
Proxies can be defined directly on a Model like so:
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 model的Stroe都需要以同样的方式加载数据,这样就使我们避免重复定义每个Stroe的Proxy。
第二,我们现在不需要Store 就可以载入和保存模型Model:
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:
// Gives us a reference to the User class
var User=Ext.ModelMgr.getModel('User');
var ed =Ext.create('User',{
name:'Ed Spencer',
age :25
});
//我们能直接保存Ed,而不用把他先加到Store里。
//因为我们配置的RestProxy会自动发POST消息到url /users
//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'));
}
});
也有利用HTML5新功能优势的代理, -LocalStorage和SessionStorage。
虽然旧的浏览器不支持HTML5的这些新API,但是这个技术前景极好。
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.
Example of a Model that uses a Proxy directly
5关联Associations
Models可以用Associations API联系在一起。
大多数应用程序处理许多不同的Models,Models几乎都是相关的。
一个博客应用程序可能有User,Post和CommentModel。
用户可以创建文章,文章可以收到评论。
我们可以像这样表达这些关系:
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:
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'
});
可以很容易地表达您的应用程序中的不同Models之间的丰富关系。
每个模型可以有任意数量的Associations与其他Models关联,Models可以按照任何的顺序定义。
一旦我们有一个Models的实例,我们可以很容易地遍历相关的数据- 例如,如果我们想记录每个文章上给定用户的所有评论,我们可以这样做:
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:
// 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'));
ments().each(function(comment){
console.log(comment.get('message'));
});
});
}
});
在我们上面创建的每一个hasMany关联的结果都会产生一个新的函数添加到Model中。
我们定义User model hasMany Posts,会新增user.posts()函数供我们在上面的代码片段使用。
调用guser.posts()返回Post model的Store配置。
反过来,Post model获取comments() 函数是因为我们设置的Comments的hasMany关联。
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. Callinguser.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.
关联不仅仅用于加载数据–创建新纪录的时候也非常有用:
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();
在这里,我们实例化一个新的Post(文章),user_id字段会自动填充上用户ID。
调用sync()通过其配置的Proxy保存新Post - 这又是一个异步操作。
如果你想操作完成时发送通知,也可以添加一个回调(callback)。
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.
belongsTo关联也可以生成新的Model方法,可以这样使用这些方法:
The belongsTo association also generates new methods on the model, here's how we can use those:
// 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');
}
}
});
再次,加载函数(getUser)是异步的,需要一个回调函数来获取用户实例。
setUser方法只需更新foreign_key(这里是user_id)为100并保存Post model。
像往常一样,可以在已完成保存操作时触发回调- 无论成功与否。
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.
6加载嵌套数据Loading Nested Data
你也许会奇怪,为什么我们发送一个成功函数到User.load的调用,但在访问用户的文章和评论时却没有这样做。
这是因为上面的例子中假定,当我们提出请求获取一个用户,服务器返回的用户数据会嵌套所有的文章和评论。
通过设立象我们上面那样的关联,框架可以自动
解析出嵌套在单一请求中的数据。
框架不是先获取用户数据,然后调用另一个请求获取文章数据,然后再发出更多的请求获取评论,而是在一个服务器响应里返回所有数据:
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:
{
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'
}
]
}
]
}
]
}
数据全部是框架自动分析的。
可以很容易地配置Model的代理加载任何地方的数据,用他们的Reader来处理几乎任何返回的格式。
至于Ext JS3,整个框架的许多组件都用到了Model和Store,如Grids, Trees and Forms。
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.
Associations and Validations演示了Model的使用。
See the Associations and Validations demo for a working example of models that use relationships.
当然,它可以用非嵌套的方式来加载数据。
如果你需要“懒加载(只有被需要的时候才会加载)”,这就会有用了。
我们只是像以前那样加载User数据,但我们假设响应只包含User数据而没有任何关联的Post。
然后,我们将在回调中添加一个调用user.posts().load()的方法,以获得相关的Post数据。
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:
// 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'));
ments().each(function(comment){
console.log(comment.get('message'));
});
});
}
});
}
});
全部的事例见Lazy Associations。
For a full example see Lazy Associations
7Validations
Ext JS4Model的数据验证变得更丰富了很多。
为了证明这一点,我们要用上述关联的例子。
首先,让我们添加一些验证的User model:
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.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”的任何东西。
一些验证采取额外的可选配置- 例如长度验证可以采取Min和Max属性,格式可以用正则表达式等等。
有五个Ext JS的内置验证,添加自定义的规则也很容易。
首先,让我们看看内置验证:
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:
∙presence 确保该字段有一个值。
计数0有效,但是空字符串无效。
∙length 确保一个字符串在最小和最大长度之间。
这两种约束是可选的.
∙format 确保一个字符串匹配一个正则表达式格式。
在上面的例子中,我们必须确保年龄字段是由至少一个字母后面跟4个数字组成(译者:这里可能有错误?)。
∙inclusion 确保值是特定的值(例如确保性别是男性或女性)。
∙exclusion 确保不是某值(例如列入黑名单的username,像是“admin”)。
∙presence simply ensures that the field has a value. Zero counts as a valid value but empty strings do not.
∙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 is 4 numbers followed by at least one letter.
∙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').
现在,我们已经掌握了不同的验证都是做什么的,让我们尝试对用户实例中使用它们。
我们将创建一个用户,并针对它运行验证,并指出任何错误:
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
这里的主要是validate()方法,它运行所有配置的验证,并返回一个错误对象。
这个简单的对象只是一个任何被发现的错误的集合。
还有一些方便的方法,比如isValid(),如果任何字段都没有错误就返回true。
getByField(),它返回一个给定字段中的所有错误。
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 - and getByField(), which returns all errors for a given field.
例子参见Associations and Validations。
For a complete example that uses validations please see Associations and Validations。