资讯专栏INFORMATION COLUMN

Extjs - model总结

EastWoodYang / 741人阅读

摘要:数据读取器相当于原始数据格式与标准数据格式之间的桥梁,它屏蔽了原始数据格式不同对程序开发造成的影响。零是有效的,但空字符串无效。

用了Extjs快一年了,这里整理一下model。

数据模型

Extjs 中数据包总共包含了40多个类,其中有三个类比其他类有更重要的地位,它们分别是:modelstoreproxy,这些类在大部分的应用系统中都会用到并且得到了大量卫星类的支持,如上图。数据包的中心是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.LocalStorageExt.data.proxy.SessionStorageExt.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 确保该字段的值必须在一个特定的集合中。

exclusioninclusion相反,确保该字段的值不在某个特定的集合中。

-

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: ...
});

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/90854.html

相关文章

  • extjs-mvc结构实践(二):基本页面

    摘要:接着来,上一篇搭建了基本的项目骨架,到最后,其实啥也没看见。。。目标全屏显示左侧导航菜单,右侧标签页切换操作内容区域。一般模型与你后台返回的数据结构一一对应。给其他组件提供一致接口使用数据。整个构成一个所谓的。 接着来,上一篇搭建了基本的项目骨架,到最后,其实啥也没看见。。。书接上回,开始写UI效果。 目标 全屏显示、左侧导航菜单,右侧标签页切换操作内容区域。包含header和foo...

    changfeng1050 评论0 收藏0
  • extjs-mvc结构实践(四):导航菜单与控制器模块联动

    摘要:根据模块创建模块失败。在中,我们配置了标明了这是一个控制器模块,点击后会去触发控制器加载动作。正常情况下同一个模块的只加载一次。 前面几篇文档,我们基本实现了一个静态的extjs页面,本篇开始,实现左侧导航树与右侧内容的联动,也就是点击导航菜单,加载对应模块页面和业务逻辑,实现js文件的按需加载。 业务需求是这样的: 左侧的treelist,当点击某个节点的时候,系统根据tree数据里...

    figofuture 评论0 收藏0
  • extjs-mvc结构实践(五):实现用户管理的增删改查

    摘要:而且上一篇文章中,也已经实现了一个基本的用户管理列表页面。接着上一篇,完善用户管理,实现增删改。为了用户体验,增加和修改用户信息的表单,都放在弹窗中进行。 经过前面几篇文章的介绍,一个基本的MVC结构应该是具备了。而且上一篇文章中,也已经实现了一个基本的用户管理列表页面。接着上一篇,完善用户管理,实现增删改。为了用户体验,增加和修改用户信息的表单,都放在弹窗中进行。避免跳转页面。 定义...

    wendux 评论0 收藏0
  • Extjs 笔记

    摘要:前言本文章为平时工作是遇到的一些特效,不定时更新,并非完全原创,如有意见或建议,请在下方留言,我会做出相应补充或处理。自适应宽度复制按钮实现通过点击按钮将特定内容复制到浏览器剪贴板的功能。 前言 本文章为平时工作是遇到的一些Extjs特效,不定时更新,并非完全原创,如有意见或建议,请在下方留言,我会做出相应补充或处理。 grid 鼠标悬浮提示 通过列的render属性改变样式 func...

    zhouzhou 评论0 收藏0
  • extjs-mvc结构实践(一):搭建基础架构

    摘要:今天开始,一点点记录一下使用搭建一个基础结构的过程。没办法,记性差这种结构的前端,主要是面向后台信息管理系统,可以最大限度的规范前端代码结构和数据结构。 今天开始,一点点记录一下使用extjs6.2.0搭建一个基础MVC结构的过程。没办法,记性差:)这种结构的UI前端,主要是面向后台信息管理系统,可以最大限度的规范前端代码结构和数据结构。做网站 或者手机端,这种方式全引入了extjs,...

    kamushin233 评论0 收藏0

发表评论

0条评论

EastWoodYang

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<