用了Extjs快一年了,这里整顿一下model。
数据模子
Extjs 中数据包统共包含了40多个类,其中有三个类比其他类有更重要的职位,它们离别是:model
、store
和proxy
,这些类在大部份的运用体系中都会用到而且得到了大批卫星类的支撑,如上图。数据包的中心是Ext.data.Model
,一个model代表体系中的一些数据的范例,比方:我们的效果治理体系中的论文、专利、嘉奖的model。它是实在天下中实体对象在运用体系中的反应。
model和store
我们来看下在Ext中model代码:
Ext.define('Srims.model.patent.patents', {
extend: 'Ext.data.Model',
fields: [
{ name: 'id', type: 'int', mapping: 'Id'},
{ name: 'Title', type: 'string', mapping: 'Title'},
{ name: 'PatentNumber', type: 'string', mapping: 'PatentNumber'},
{ name: 'PatentType', type: 'string', mapping: 'PatentType'},
{ name: 'PatentStatus', type: 'string'},
{ name: 'AuthorizeDateTime',type: 'string', mapping: 'AuthorizeDateTime'},
{ name: 'DepartmentId', type: 'int'},
{ name: 'DepartmentName', type: 'string', mapping: 'DepartmentName'},
{ name: 'ResponsorName', type: 'string', mapping: 'ResponsorName'},
{ name: 'Status', type: 'string'}
]
});
这是一个最简朴的model,只要fields,接下来我们还会讲到model的四个重要的部份–Fields,Proxy,Association 和 Validations。
平常,model和store一同运用,假如说model是数据的范例,它的实例是一条数据纪录,那末store实例是model实例的鸠合,建立一个store而且加载数据。
Ext.define("Srims.store.patent.patents", {
extend: 'Ext.data.Store',
model: 'Srims.model.patent.patents',
proxy: {
type: 'ajax',
url:'http://222.195.150.214:24367/api/patents/getbystatus/1',
reader: {
type: 'json',
root: 'DataList',
successProperty: 'success'
}
},
autoLoad: true
});
我们给store设置了一个Ajax Proxy(背面讲),通知他URL,让它从这个处所猎取数据,还配了reader去剖析数据(reader背面也讲),服务器返回Json,所以我们建立了一个Json reader 去读取相应(response)。Store自动加载一组model 实例,就像如许
Store还供应了对数据的过滤、排序、分组的功用:
Ext.define("Srims.store.patent.patents", {
extend: 'Ext.data.Store',
model: 'Srims.model.patent.patents',
//……
sorters: ['Title', 'id'];
filters: {
property: 'DepartmentName',
value: '信息科学与工程学院'
}
groupField: 'status',
groupDir: 'Desc'
});
在这个store中,我们将数据先按称号排序,再按Id排序;然后过滤为只要学院为信息科学与工程学院的纪录,别的,依据纪录状况根据降序分组。
由于store API中有许多有关的要领,能够依据须要随时变动store的排序、过滤、分组体式格局。比方,在效果治理体系中,所属项目列表,我要将列表中状况为增加(A)和删除(D)的纪录拿出来,就能够运用filter。
//给store增加过滤器
store.filter([
function(item) {
return (item.data.Status == 'A') || (item.data.Status == 'D');
}
]);
……
//消灭过滤器
store().clearFilter();
肯定要注意,肯定要在完毕后加上这句store().clearFilter(); 将该过滤器消灭,不然以后store中就只要这些过滤后的数据。
上图清楚地展现了model的4个重要组成部份。(字段定义、数据代办、模子关联、数据校验)。
proxy
Proxy被用来对model数据的读取和保留的,有两种proxy:客户端proxy(Ext.data.proxy.Client
)和服务器端proxy(Ext.data.proxy.Server
),它们都继续自Ext.data.proxy.Proxy
类。
Ext.data.proxy.Client
是在客户端举行数据存取操纵的基类,平常不会举行实例化,而是运用它的子类。Ext.data.proxy.Memory
运用内存变量存取数据:Ext.data.proxy.LocalStorage
和Ext.data.proxy.SessionStorage
是Ext.data.proxy.WebStorage
运用HTML5的新特征DOM Storage机制,用于存储键值对。SessionStorage用于存储与当前浏览器窗口关联的数据,窗口封闭后,sessionStorage中存储的数据将没法运用;localStorage用于历久存储数据,窗口封闭后,localStorage中的数据依然能够被接见,一切浏览器窗口能够同享localStorage的数据。
Ext.data.proxy.Server
是服务器端代办的父类,平常也不举行实例化。与客户端代办差别,服务器代办会接见长途的服务器资本,适合于历久保留重要的数据资料。
Ext.data.proxy.Ajax
Ext.data.proxy.Ajax
代办是一个在运用顺序中运用最普遍的服务器端代办(也是效果治理体系中重要运用的代办),它采纳Ajax体式格局经由过程要求指定的URL来读写数据,他不能读取跨域数据(Ext.data.proxy.JsonP
重要用于跨域读取数据)。
效果体系中当时由于index.html文件在当地,要要求214服务器上的数据,产生了跨域题目,厥后把index文件页放在214上,要求同在214上的数据,避免了跨域题目。
Ajax代办提议要求是会自动插进去sorting排序、filtering过滤、paging分页和grouping分组设置到每个要求中,在效果体系中,在store中如许设置,完成分页:
Ext.define("Srims.store.achievementAudit.auditPatentList", {
extend: 'Ext.data.Store',
model: 'Srims.model.patent.patents',
pageSize : 40, //分页-每页纪录数
proxy: {
type: 'ajax',
url: Srims.api.patentlist + '2',
reader: {
totalProperty: ‘TotalRecordCount’, //猎取接收到的数据的纪录总数
type: 'json',
root: 'DataList',
successProperty: 'success'
}
},
autoLoad: true
});
reader数据读取器
数据读取器重要用于将数据代办读取到的原始数据根据差别的划定规矩举行剖析,将剖析后的数据保留在Model模子对象中。数据读取器相当于原始数据格式与Extjs规范数据格式之间的桥梁,它屏障了原始数据格式差别对顺序开辟形成的影响。在Extjs中供应的数据剖析器重要有以下3种:
Ext.data.reader.Json (JSON数据读取器)
Ext.data.reader.Xml (XML数据读取器)
Ext.data.reader.Array (数组数据读取器)
reader: {
type: 'json',
root: 'DataList', //返回信息的属性名
totalProperty: 'TotalRecordCount', //猎取纪录总数的属性名
}
writer数据写入器
数据写入器重要用于将数据代办提交到服务器的数据举行编码,相当于Extjs规范数据格式与服务器数据格式之间的桥梁,他屏障了服务器端数据格式差别对顺序开辟形成的影响。在Extjs中供应的数据写入器有:
Ext.data.writer.Json (Json写入器)
Ext.data.writer.Xml (xml写入器)
—
Ext.define("User", {
extend:"Ext.data.Model",
fields:[
{name:'name', type:'string'},
{name:'age', type:'int'}
],
proxy:{
type : "ajax",
url : " fakeData.jsp",
writer:{
type : "json"
}
}
});
var user = Ext.ModelMgr.create({
name: "Tom",
age: 24
} ,"User");
user.save();
Ext.data.proxy.Rest
Ext.data.proxy.Rest是一个特殊化的Ajax代办,将四种行动(create,read,update和destroy)映射到四种restful http动词(put,get,post和delete)上,将要求的URL转化为rest作风,轻易举行rest作风的web运用开辟。
rest代办会依据前端框架状况,推断要实行的操纵,从而推断用什么要领及须要接见的资本,终究肯定URL。比方,在挪用save要领时,会自动推断Model的id属性是不是有值假如有就运用update途径,假如没有就运用create途径:
Ext.define('User', {
extend: 'Ext.data.Model',
fields: ['id', 'name', 'email'],
proxy: {
type: 'rest',
url : '/users'
}
});
var user = Ext.create('User', {
name: 'Ed Spencer',
email: 'ed@sencha.com'
});
user.save(); //POST /users
//扩大save,增加回调函数
user.save({
success: function(user) {
user.set('name', 'Khan Noonien Singh');
user.save(); //PUT /users/123
}
});
user.destroy(); //DELETE /users/123
association
在运用体系中总会有差别的模子,这些模子之间大部份状况下是有关联的,比方,效果体系中,论文和作者、专利和发明人、嘉奖和获奖人之间存在一对多的关联,在Extjs4中支撑的关联关联包含一对多和多对一两种,离别经由过程Ext.data.HasManyAssociation
类和Ext.data.BelongsToAssociation
类完成。
这是官网上的一个例子:
//用户model
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' }
});
//帖子model
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: 'Comment
});
//批评model
Ext.define('Comment', {
extend: 'Ext.data.Model',
fields: ['id',
'post_id',
'name',
'message‘
],
belongsTo: 'Post'
});
关于读数据
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'));
});
});
}
});
load Id为1的user,而且经由过程user的proxy load了相干的post和comment。
每个我们建立的hasMany关联就会有个新的要领增加到这个model。依据name生get要领,不然自动天生默许的model名字小写加s,user.posts()
,挪用该要领,会返回一个配有post model的store,一样,post获得了一个comments()
要领。
数据大概是这个模样的:
{
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'
}]
}]
}]
}
关于写数据
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(); //经由过程设置好的proxy保留新的纪录
association联络不仅能协助我们读数据,它对建立新的纪录也有协助(代码)我们建立了一条新的帖子,给了当前user的Id为user_Id的纪录。挪用sync()
要领经由过程设置好的proxy保留新的纪录,这是异步的操纵,我如我们想在操纵胜利后做其他操纵能够在里面增加回调函数。
连系前两部份的一个例子
一个专利对应多个发明人。
//专利详细信息model
Ext.define('Srims.model.patent.patentDetail', {
extend: 'Ext.data.Model',
fields: [
{ name: 'id', type: 'int'}
{ name: 'patentName', type: 'string'},
{ name: 'patentNumber', type: 'string'},
……
],
hasMany: { model: 'Srims.model.patent.inventors',
name: 'Owners',
associationKey: 'Owners',
foreignKey: 'patentId'
}
proxy: {/*??*/}
});
//发明人model
Ext.define('Srims.model.patent.inventors', {
extend: 'Ext.data.Model',
fields: [
{ name: 'Id', type: 'int' },
{ name: 'Ordinal', type: 'int' },
{ name: 'Name', type: 'string' },
……
{ name: 'patentId', type: 'int'}
]
belongsTo: 'Srims.model.patent.patents'
proxy: {/*??*/}
});
URL中都须要参数,那末proxy怎样设置?
Ext.define('Srims.model.patent.patentDetail', {
……
proxy: {
type: "rest",
reader: {type: "json"},
url: 'http://222.195.150.214:24367/api/patents'
}
});
var patentModel = Ext.ModelManager.getModel('Srims.model.patent.patentDetail');
patentModel.load(3017);
有关发明人的URL中心某个位置须要参数……
增加一条发明人纪录:POST http://222.195.150.214:24367/api/patents/{patentId}/patentInventors
修正一条发明人纪录:PUT http://222.195.150.214:24367/api/patents/{patentId/patentInventors/{ordinal}
Ext.define('Srims.model.patent.inventors', {
extend: 'Ext.data.Model',
……
proxy: {
type: "rest",
reader: {type: "json"},
url: 'http://222.195.150.214:24367/api/patents/{}/patentInventors',
//重写buildUrl
buildUrl: function(request) {
var me = this,
operation = request.operation,
records = operation.records || [],
record = records[0],
url = me.getUrl(request),
id = record && record.get("patentId");
Ordinal = record && record.get("Ordinal");
if (me.isValidId(id)) { //将{}替换为patentId
url = url.replace('{}', id);
} else {
throw new Error('A valid id is required');
}
if (operation.action === “update”) { //若为修正操纵,在URL末端加上位次
url += '/' + Ordinal;
}
request.url = url;
return Ext.data.proxy.Rest.superclass.buildUrl.apply(this, arguments);
}
}
});
读写发明人:
var patentModel = Ext.ModelManager.getModel('Srims.model.patent.patentDetail');
patentModel.load(3017, {
success: function (record) {
record.Owners().add({
Ordinal: 6,
Name: "zhanglu"
});
record.Owners().getNewRecords()[0].save({ //增加一条纪录 post
success: function(){
record.Owners().sync(); //将其他纪录同步(equal to修正)put
}
});
}
});
validation
presence
保证了字段有值。零是有用的,但空字符串无效。length
确保了一个string范例的字段长度必需在最大值和最小值之间,两个值都是可选的。format
确保字符串必需与正则表达式婚配。inclusion
确保该字段的值必需在一个特定的鸠合中。exclusion
与inclusion
相反,确保该字段的值不在某个特定的鸠合中。
–
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: ...
});