数据包用来加载和保存所有的应用程序中的数据,由41类组成。但是有三个更重要——
Model,
Store 和
Ext.data.proxy.Proxy.。
代理可以就像这样直接定义在一个模型上:
我们发出获得用户信息的请求,服务器返回的用户数据加上它的所有嵌套的文章和评论。通过我们上面建立的联系,框架可以在一个单一的请求中自动解析出嵌套的数据。与其先请求用户数据,再请求贴子的数据,然后更多的请求来加载每个帖子的评论,还不如在单一服务器响应中可以返回所有数据如下:
同样,可以在非嵌套的样式中加载数据。如果你只有在需要时"lazy load"关联数据,这种方法很有用。这时响应只有用户数据,而没有关联数据。我们将会在我们的回调函数中添加一个user.posts().load()来获得相关的Post数据:
一、模型和存储库
在数据包的中心是Ext.data.Model。一个模型代表了应用程序中某种类型的数据——例如:一个电子商务应用程序有用户、产品和订单的模型。最简单的模型仅仅是一组字段和他们的数据。模型四要素—字段、代理、关联和验证。创建一个模型:
Ext.define('User', {
extend: 'Ext.data.Model',
fields: [
{ name: 'id', type: 'int' },
{ name: 'name', type: 'string' }
]
});
模型通常和存储库一起用:
Ext.create('Ext.data.Store', {
model: 'User',
proxy: {
type: 'ajax',
url : 'users.json',
reader: 'json'
},
autoLoad: true
});
我们使用Ajax代理来配置存储库,告诉它加载数据的url和用来解码数据的reader。在这种情况下,服务器返回JSON,所以我们已经设置了一个JSON Reader来读取响应。存储库从users.json中自动加载一组用户模型实例。
users.json
返回一个json。如下:
{
success: true,
users: [
{ id: 1, name: 'Ed' },
{ id: 2, name: 'Tommy' }
]
}
二.内联数据
Ext.create('Ext.data.Store', {
model: 'User',
data: [
{ firstName: 'Ed', lastName: 'Spencer' },
{ firstName: 'Tommy', lastName: 'Maintz' },
{ firstName: 'Aaron', lastName: 'Conran' },
{ firstName: 'Jamie', lastName: 'Avins' }
]
});
这时,store将data中的每个对象转化成模型实例
三.排序和分组
存储库都能够执行排序、筛选和分组:Ext.create('Ext.data.Store', {
model: 'User',
sorters: ['name', 'id'],
filters: {
property: 'name',
value : 'Ed'
},
groupField: 'age',
groupDir: 'DESC'
});
数据将首先按名称排序然后id,它将过滤只包括名字为“Ed”的用户,而数据将按年龄分组降序排列。
四.代理
有两种类型的代理:客户端和服务器。客户机代理的例子包括浏览器内存中存储数据的内存和使用HTML 5的本地存储特性的本地存储。服务器代理将处理的数据编组到一些远程服务器,例子包括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'
});
这样每个使用这个用户模型存储库都将以相同的方式加载它的数据,所以我们可以为每个存储避免复制代理定义。而且我们无需存储就可以加载和保存模型数据:
// 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'));
}
});
五.关联
用关联API可以把模型连接在一起。大多数应用程序处理许多不同的模型,而且模型几乎都是相关的。我们可以这样表达关联: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'
});
在应用程序中很容易表达不同模型之间的丰富关系。每个模型可以与其它模型有任意数量的关联,模型可以以任何顺序定义。一旦我们拥有了一个模型实例我们可以轻松地遍历它关联的数据——例如,如果我们想要记录每个帖子(Post)对于给定的用户(
User
)的所有言论(
Comment
),我们可以这样做:
// 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'));
});
});
}
});
我们前面创建的每个hasMany联系都能促使一个新函数添加到模型中。我们声明每个用户模型有很多帖子,则就添加了user.posts()函数。调用user.posts()返回一个配置了Post模型的存储。反过来,Post模型得到一个
关联不仅仅可以用来加载数据,也适用于创建新的记录:
comments
()函数,因为我们设置了一个帖子有多个评论。
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()通过其配置代理保存新帖子,而且它是一个异步操作,如果你希望当操作完成时得到通知,可以传递一个回调。
belongsTo关联也在模型上生成新方法:
// 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为100,并保存Post模型。像往常一样,当保存操作已经完成——无论成功与否,回调函数将被触发。
我们发出获得用户信息的请求,服务器返回的用户数据加上它的所有嵌套的文章和评论。通过我们上面建立的联系,框架可以在一个单一的请求中自动解析出嵌套的数据。与其先请求用户数据,再请求贴子的数据,然后更多的请求来加载每个帖子的评论,还不如在单一服务器响应中可以返回所有数据如下:
{
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'
}
]
}
]
}
]
}
数据都是由框架自动解析。很容易配置您的模型的代理来从几乎任何地方加载数据,他们的Reader来处理几乎所有的响应格式。
同样,可以在非嵌套的样式中加载数据。如果你只有在需要时"lazy load"关联数据,这种方法很有用。这时响应只有用户数据,而没有关联数据。我们将会在我们的回调函数中添加一个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'));
});
});
}
});
}
});
六.验证
在用户模型中添加验证: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个字符长度,年龄字段是一个数字,性别字段要么“男性”或“女性”,并且用户名绝不会是“admin”。一些验证采取额外的可选配置——例如长度验证可以采取min和max属性,格式可以采取一匹配器,等。有五个验证构建到Ext JS,增加自定义规则是很容易的。
presence
:确保字段有一个值,0作为有效值,但空字符串不算length
:确保字符串的长度处于最大长度和最小长度之间。两个约束是可选的format
:确保字符串匹配正则表达式。inclusion:
确保值包含着特定的值之中exclusion
:确保值不在特定的值之中
// 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(),它返回对于给定的字段的所有错误。