用了Extjs快一年了,这里整理一下model。html
Extjs 中数据包总共包含了40多个类,其中有三个类比其余类有更重要的地位,它们分别是:model
、store
和proxy
,这些类在大部分的应用系统中都会用到而且获得了大量卫星类的支持,如上图。数据包的中心是Ext.data.Model
,一个model表明系统中的一些数据的类型,好比:咱们的成果管理系统中的论文、专利、奖励的model。它是真实世界中实体对象在应用系统中的反映。前端
咱们来看下在Ext中model代码:web
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'} ]
});ajax
这是一个最简单的model,只有fields,接下来咱们还会讲到model的四个主要的部分--Fields,Proxy,Association 和 Validations。正则表达式
一般,model和store一块儿使用,若是说model是数据的类型,它的实例是一条数据记录,那么store实例是model实例的集合,建立一个store而且加载数据。json
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 实例,就像这样api
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被用来对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
代理是一个在应用程序中使用最普遍的服务器端代理(也是成果管理系统中主要使用的代理),它采用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 });
数据读取器主要用于将数据代理读取到的原始数据按照不一样的规则进行解析,将解析后的数据保存在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', //获取记录总数的属性名 }
数据写入器主要用于将数据代理提交到服务器的数据进行编码,至关于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是一个特殊化的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
在应用系统中总会有不一样的模型,这些模型之间大部分状况下是有关联的,好比,成果系统中,论文和做者、专利和发明人、奖励和获奖人之间存在一对多的关系,在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 } }); } });
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: ... });