Sencha ExtJS5.x 的数据包Data Package讲解

数据包是你应用程序加载和保存所有数据的地方。它包含大量的类,其中有三个比其它所有的都更重要。

它们是: Ext.data.Model / Store /Ext.data.proxy.Proxy

这三个类几乎被所有的应用程序使用,并且得到了许多周围类来支持。


data package

Models模型

数据包的核心就是Ext.data.Model.一个模型就在应用程序中代表了一个实体,举个例子,一个电子商务应用程序可能需要有用户、商品和订单,最基本的层次上来说,一个模型就定义了一系列的字段和其相关联的业务逻辑。

我们可以看一下模型的几个主要部分:

Fields/ Proxies/ Validations/Associations


模型组成

创建一个模型

通常来说,使用一个基类来定义你的模型是一个好的选择。这个基类可以方便你在一个地方对你的模型进行特定的配置,这样也方便配置schema,schema是你应用程序所有模型的管理器,现在我们可以先重点关注下两个比较有用的配置选项:

Ext.define('MyApp.model.Base',{

    extend: 'Ext.data.Model',


    fields: [{

        name: 'id',

        type: 'int'

    }],


    schema: {

        namespace: 'MyApp.model',  // generate auto entityName


        proxy: {     // Ext.util.ObjectTemplate

            type: 'ajax',

            url: '{entityName}.json',

            reader: {

                type: 'json',

                rootProperty:'{entityName:lowercase}'

            }

        }

    }

});

不同的应用程序在基类模型中会有不同的内容,尤其是fields.

Proxies代理

代理是在Models和Stores中使用的,它负责加载和保存模型的数据。有两种不同类型的代理:客户端和服务端(Client And Server).

代理可以直接在基类model的schema中定义,比如上面的代码例子。

客户端代理

客户端的例子有Memory和Local

Storage,使用了HTML5的localstorage特性。尽管旧的浏览器不支持这些新的HTML5 AP,但是它在实际应用中是非常有用的。

服务端代理

服务端代理负责封装远程服务的数据,例子有AJAX/JSONP/REST。

Schema

Schema是一系列有彼此关联的实体。当一个模型配置了schema,所有的衍生类都会继承。上述例子中,schema已经默认给所有的模型配置了两个默认属性。

第一个配置是namespace命名空间,通过指定这个命名空间,所有实体都拥有了一个缩略名,缩略名在定义实体关联关系的时候非常重要。

第二个配置是 代理proxy,这是一个类模板,跟Ext.XTemplete有点类似。不同的就是类模板在给定数据的时候产生的是对象,在此指定之后,没有显示指定proxy的都会使用该proxy.

应用程序中很可能会存在这种微小差异但又绝大多数相同的请求,通过这样配置,可以减少每个模型直接的重复定义proxy。

User.json被我们指定为url:{entityName.json},应该返回JSON字符串。在例子中我们使用的是

{

  "success": "true",

  "user": [

    {

      "id": 1,

      "name": "Philip J.Fry"

    },

    {

      "id": 2,

      "name": "HubertFarnsworth"

    },

    {

      "id": 3,

      "name": "TurangaLeela"

    },

    {

      "id": 4,

      "name": "Amy Wong"

    }

  ]

}

Stores

通常情况下model模型会配合store一起使用,store是一系列的records记录的集合,而record是一个模型驱动的类的实例,下面的例子是一个创建store和加载数据的:

var store = new Ext.data.Store({

    model: 'MyApp.model.User'

});


store.load({

    callback:function(){

        var first_name =this.first().get('name');

         console.log(first_name);

    }

});

我们手动加载store来获取一系列的MyApp.model.User的记录,这些记录在加载完成后会在回调事件中打印出来。

内联数据Inline data

Store可以加载内联数据,store根据我们传入的对象加载到模型适合的类型中去。

new Ext.data.Store({

    model: 'MyApp.model.User',

    data: [{

        id: 1,

        name: "Philip J. Fry"

    },{

        id: 2,

        name: "Hubert Farnsworth"

    },{

        id: 3,

        name: "Turanga Leela"

    },{

        id: 4,

        name: "Amy Wong"

    }]

});

排序和分组

Stores可以执行排序,分组和过滤,可以是本地的也可以是服务端的。

new Ext.data.Store({

    model: 'MyApp.model.User',


    sorters: ['name','id'],

    filters: {

        property: 'name',

        value  : 'Philip J. Fry'

    }

});

在这个store中,数据通过name和id排序,数据会过滤只加载包含Philip J. Fry的用户,通过API可以随时对这些属性进行调整修改。

Associations关联关系

模型可以通过关联关系API聚合到一起,多数应用程序会处理很多模型,并且模型直接存在关系。一个授权博客程序可能会有用户和发稿,每一个用户创建很多稿件,所以一个用户可能会存在多个发稿,但是一个稿件只能被一个用户发布,这就是大家熟知的多对一关系,我们在ExtJS中这样表达:

Ext.define('MyApp.model.User',{

    extend: 'MyApp.model.Base',


    fields: [{

        name: 'name',

        type: 'string'

    }]

});


Ext.define('MyApp.model.Post',{

    extend: 'MyApp.model.Base',


    fields: [{

        name: 'userId',

        reference: 'User', // the entityNamefor MyApp.model.User

        type: 'int'

    }, {

        name: 'title',

        type: 'string'

    }]

});

在应用程序中对丰富的关系模型进行表述可以说是很方便了。每一个模型都可以有任意数量的对其他模型的关联关系。另外,你的模型定义的顺序也可以比较随意,一旦你有了这个模型的类型,你就可以方便的遍历关联数据了。比如,你想获取一个用户所有的发稿,你就可以这样做:

// Loads User with ID 1 andrelated posts and comments

// using User's Proxy

MyApp.model.User.load(1, {

    callback: function(user) {

        console.log('User: ' +user.get('name'));


        user.posts(function(posts){

            posts.each(function(post) {

                console.log('Post: ' +post.get('title'));

            });

        });

    }

});

上述代码是说,model新增了一个方法user.posts(),每一个用户都有许多发稿,调用user.posts()就会返回Post模型配置的store。

关联关系不仅在加载数据的时候有用,在创建新的记录的时候也可以用:

user.posts().add({

    userId: 1,

    title: 'Post 10'

});


user.posts().sync();

这个实例创建了一个新的发稿,自动赋值用户ID给ID字段,调用sync()方法通过proxy保存新的发稿,这是异步的方法,所以你可以设置当完成操作的时候进行回调。

逆关联关系在Post模型中也会产生新的方法:

MyApp.model.Post.load(1, {

    callback: function(post) {


        post.getUser(function(user) {

            console.log('Got user from post: '+ user.get('name'));

        });                          

    }

});


MyApp.model.Post.load(2, {

    callback: function(post) {

        post.setUser(100);                        

    }

});

加载方法getUser()是异步的,需要一个回调来创建用户实例,setUser()方法仅仅就是更新了用户id为100并且保存了Post模型,跟以前一样,可以通过保存操作的返回成功与否触发回调。

加载嵌入数据

当关联关系定义好之后,单请求可以同时请求到关联数据,比如,看下面的返回值;{

    "success": true,

    "user": [{

        "id": 1,

        "name": "Philip J.Fry",

        "posts": [{

            "title": "Post1"

        },{

            "title": "Post2"

        },{

            "title": "Post3"

        }]

    }]

}

通过单请求,可以同时获取用户和用户下的文章,儿不必先请求用户,再根据用户获取下面的发稿。

验证

模型同时也提供了对数据校验的一大群支持,为了进行演示,我们通过上述例子进行构造数据,我们给用户模型增加了一些数据校验:

Ext.define('MyApp.model.User',{

    extend: 'Ext.data.Model',

    fields: ...,


    validators: {

        name: [

            'presence',

            { type: 'length', min: 7 },

            { type: 'exclusion', list: ['Bender']}

        ]

    }

});

校验定义一个name字段,对该字段进行校验,校验规则就是name字段下配置的对象,例子说的是对name字段进行校验,校验规则是长度不得少于7个字符,数据可以是除了Bender之外的任何数据。

有些严重包含其他一些配置选择,比如长度可以有最长和最短,max min属性,格式化可以使用matcher等,ExtJS提供了五个校验,用户自定义校验也很简单:

Presence-确保该字段必须存在值,不允许有空字符串。

Length-确保字符串有正确的长度,最大最小都是可选的。

Format-确保字符串满足正则表达式的格式。

Inclusion-确保值包含我们要求的。

Exclusion-确保值不包含我们要求的。

下面可以通过用户实例来尝试使用校验,我们创建一个用户,进行校验的:

// now lets try to create anew user with as many validation

// errors as we can

var newUser = newMyApp.model.User({

    id: 10,

    name: 'Bender'

});


// run some validation on thenew user we just created

console.log('Is User valid?',newUser.isValid());


//returns 'false' as therewere validation errors


var errors =newUser.getValidation(),

    error = errors.get('name');


console.log("Error is:" + error);

关键方法就是getValidation(),通过该方法进行校验和返回校验结果,校验记录是懒加载的并且需要的时候才更新。

上面的结果是:Length must be greater than 7

所以我们提供一个大于7个字符的字符:

newUser.set('name', 'BenderBending Rodriguez');

errors =newUser.getValidation();

这样,所有条件都被满足了,调用newUser.isValid()返回true,当我们调用getValidation()就能保证字段都是正常的了。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,026评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,655评论 1 296
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,726评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,204评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,558评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,731评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,944评论 2 314
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,698评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,438评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,633评论 2 247
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,125评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,444评论 3 255
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,137评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,103评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,888评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,772评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,669评论 2 271

推荐阅读更多精彩内容