数据包(Data Package)是负责加载和保存在Sencha Touch应用程序的所有数据。
它涉及到三个部分:model, store, proxy(模型、商店、代理)。
model:model表示你的工程所关心的实体。用户,联系人,地址,和产品都可以被模型。在其最简单的,一个模型只是一个收集的领域和他们的数据,但他们可以做的更多。
store:一个store是一个model实例。它主要是一个阵列,但它也提供了功能分类,过滤,分组,和它能够触发的事件。
proxy:proxy负责实际加载和保存数据到一个store。你通常会创建一个Ajax代理,将数据从服务器获取并使用它来填充一个store。
model
model含有四个主体:Fields, Proxies, Associations and Validations(域、代理、协会、验证)
Fields
下面我们就写个简单的例子:
Ext.define('User', {
extend: 'Ext.data.Model',
config: {
fields: [
{ name: 'id', type: 'int' },
{ name: 'name', type: 'string' }
]
}
});
写法可参照类,这里只定义了fields,可以指定数据类型。
Proxies
下面来说下代理,代理含有两种:客户端和服务器,客户端包含浏览器内存和本地存储,支持html5的本地存储功能。服务器包括Ajax, JsonP, 和 Rest。
Ext.define('User', {
extend: 'Ext.data.Model',
config: {
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'
});
在创建store时通过指定model:来把自己定义的user实例成store。
将proxy放到model中来是有好处的,当很多store应用一个model时不用重复的指定proxy,而且我们可以加载和保存模型数据而不调用一个存储。
// 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 which 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'));
}
});
通过上面的例子我们知道;我们可以通过Ext.ModelMgr.getModel()这种方式来获取一个已经定义过的model实例。
而且由于已经在model中定义好了proxy,所以无需store可以通过save的方式直接操作数据向url /users发送一个post请求;通过User.load方式,获取到id=1的用户。
也可以使用代理来利用HTML的本地存储和session存储(f HTML5 - LocalStorage and SessionStorage),虽然还有很多浏览器不支持,但它也许在将来发挥巨大的作用。
Associations
model可以通过Associations API连接在一起使用,因为在实际的业务中,好多的model是有些联系的。比如一个博客,有用户,和评论,用户发表评论。我们可以通过下面的例子来表达这些关系:
Ext.define('User', {
extend: 'Ext.data.Model',
config: {
fields: ['id', 'name'],
proxy: {
type: 'rest',
url : 'data/users',
reader: {
type: 'json',
root: 'users'
}
},
hasMany: 'Post' // shorthand for { model: 'Post', name: 'posts' }
}
});
Ext.define('Comment', {
extend: 'Ext.data.Model',
config: {
fields: ['id', 'post_id', 'name', 'message'],
belongsTo: 'Post'
}
});
Ext.define('Post', {
extend: 'Ext.data.Model',
config: {
fields: ['id', 'user_id', 'title', 'body'],
proxy: {
type: 'rest',
url : 'data/posts',
reader: {
type: 'json',
root: 'posts'
}
},
belongsTo: 'User',
hasMany: { model: 'Comment', name: 'comments' }
}
});
通过belongsTo:来指定上一级model,通过hasMany来指定下一级model,其中’Post’ 是对 { model: ‘Post’, name: ‘posts’}的简写。
可以看到上面模型的关系,User<-Post<-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'));
});
});
}
});
通过User.load ,得到id=1的用户数据,甚至能够获取到posts和comments.
Associations不仅有助于加载数据,也可以用于创建新记录(records):
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,然后通过配置的代理叫sync()保存新的Post。这是一个异步操作,当操作完成时你可以通过一个回调来通知你或者做些其他的操作。
以上的部分属于Associations。
最后你还可以再模型中生成新的方法包括异步的方法:
// 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');
}
}
});
Validations
我们可以在定义model时同时指定丰富的数据验证规则:
Ext.define('User', {
extend: 'Ext.data.Model',
config: {
fields: [
// ...
],
validations: [
{ type: 'presence', field: 'name' },
{ type: 'length', field: 'name', min: 5 },
{ type: 'format', field: 'age', matcher: /\d+/ },
{ type: 'inclusion', field: 'gender', list: ['male', 'female'] },
{ type: 'exclusion', field: 'name', list: ['admin'] }
],
proxy: [
// ...
]
}
});
包括presence 非空验证,length长度,format正则表达式验证,inclusion指定结果集,exclusion排除的结果。
定义好了带有验证的model后我们来使用一下:
// 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'
});
// validate()来验证我们刚刚创建的User实例
var errors = newUser.validate();
console.log('Is User valid?', errors.isValid()); // 返回验证结果,这里返回false
console.log('All Errors:', errors.items); // 返回所有不符合验证的结果
console.log('Age Errors:', errors.getByField('age')); // 返回指定的age属性的错误
这里的关键功能是validate(),运行所有的配置的验证并返回一个错误对象。
Store
说完了model,我们再来说说store
model通常都是用在store上的:
Ext.create('Ext.data.Store', {
model: 'User',
proxy: {
type: 'ajax',
url : 'users.json',
reader: 'json'
},
autoLoad: true
});
在这个例子中,我们配置了store使用Ajax代理,负载数据提供的URL的名称和读者用于解码数据。在这种情况下,服务器返回的JSON,所以我们建立了一个JSON读取器读取响应。autoLoad:true代表当store加载后就去自动读取数据。
结合着model来看,我们发现proxy可以灵活的配置在model或者store中,这要结合你工程的实际情况来用。
当然,store也可以加载内部数据:
Ext.create('Ext.data.Store', {
model: 'User',
data: [
{ firstName: 'Greg', lastName: 'Barry' },
{ firstName: 'Seth', lastName: 'Lemmons' },
{ firstName: 'Mitch', lastName: 'Simoens' },
{ firstName: 'Fred', lastName: 'Mosby' }
]
});
在创建store的同时,我们还可以直接进行排序,分组,过滤:
Ext.create('Ext.data.Store', {
model: 'User',
sorters: ['name', 'id'],
filters: {
property: 'name',
value : 'Ed'
},
groupField: 'age',
groupDir: 'DESC'
});
通过name,id来排序,只查出name=’Ed’数据,以age分组以age降序排列。
Proxy
代理,我们已经穿插的在model和store中讲了。
代理含有两种:客户端和服务器,客户端包含浏览器内存和本地存储,支持html5的本地存储功能。服务器包括Ajax, JsonP, 和 Rest。
可以定义在model中,也可以配置在store中。