数据组件包-Data Package

数据组件包是用于管理应用程序加载和存储数据,包括许多的类,最重要的是下列的三个类:

  • Ext.data.Model
  • Store
  • Ext.data.proxy.Proxy

绝大多数的应用都会使用上述的三个类,并且有很多类为这三个类提供支持。

实体模型-Models

数据组件包的核心是实体模型Ext.data.Model。一个模型对应应用的一个实体,例如:一个电商的应用可能包含 Users、Products 和 Orders 等实体。最简单的情形,每个Model定义一系列字段(field) ,这些字段与业务逻辑相关。

实体模型的主要部件:

  • 字段(Fields)
  • 代理(Proxies)
  • 验证(Validations)
  • 关联(Associations)

创建实体模型-Creating a Model

定义Model的最佳方式是从一个共通的基类扩展。该基类可以集中配置一些参数,同时也可以集中配置架构(schema)。架构是所有Model的管理者。现在聚焦一下两个最有用的配置选项:

Ext.define('MyApp.model.Base', {
    extend: 'Ext.data.Model',

    fields: [{
        name: 'id',
        type: 'int'
    }],

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

        // Ext.util.ObjectTemplate
        proxy: {
            type: 'ajax',
            url: '{entityName}.json',
            reader: {
                type: 'json',
                rootProperty: '{entityName:lowercase}'
            }
        }
    }
});

代理-Proxies

ModelStore使用代理加载和存储数据,有两种代理:客户端(Client)和服务器端(Server)。代理可以直接定义在 Model 基类的 schema 对象中(参见上述示例)。

客户端代理-Client Proxy

客户端代理的示例包括:MemoryLocal Storage(HTML5 localstorage 特性)。尽管较早的浏览器不支持 HTML5 新的 APIs,但是如果能应用这些特性,还是会给应用带来巨大的益处。

服务器端代理-Server Proxy

服务器端代理封装数据并且发送到远程服务器。例如:AJAX、JSONP 和 REST。

架构-Schema

架构是一系列相关实体的集合。当一个实体设置了 "schema" 配置,那么所有继承它的实体都继承该架构。在上述的示例中,架构设置了两个属性,这两个属性是该架构下所有实体的缺省设置。

第一个是命名空间("namespace")。通过设置命名空间,所有实体都可以获得一个简称("entityName")。这个简称在定义实体关系时非常有用。

第二个是代理("proxy")。这是一个基于Ext.XTemplate的对象模板,类似于文本模板。 不同之处在于,对象模板在获得数据后生成一个对象。在这个示例中,对于未显式定义代理的实体,将根据数据自动生成代理配置的定义。

由于实体加载数据的方式非常相似,只是加载的内容不同,所以这种方法非常有效,可以避免重复定义每个实体的代理。

在 URL(url: '{entityName}.json')中配置的 User.json 应该返回 JSON 字符串。例如:

{
  "success": "true",
  "user": [
    {
      "id": 1,
      "name": "Philip J. Fry"
    },
    {
      "id": 2,
      "name": "Hubert Farnsworth"
    },
    {
      "id": 3,
      "name": "Turanga Leela"
    },
    {
      "id": 4,
      "name": "Amy Wong"
    }
  ]
}

Stores

通常情况下,Models 与 Store 结合使用,Store 是 Model 数据记录的集合。创建一个 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);
    }
});

我们手动加载了 MyApp.model.User 的数据,加载成功后,输出第一条记录的name字段值。

内联数据-Inline data

Stores 也可以加载内联数据。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"
    }]
});

排序和分组-Sorting and Grouping

Stores 可以进行排序(sorting)、筛选(filtering)和分组(grouping),分为本地(locally)和远程(remotely)两种方式。

new Ext.data.Store({
    model: 'MyApp.model.User',

    sorters: ['name','id'],
    filters: {
        property: 'name',
        value   : 'Philip J. Fry'
    }
});

上述示例中,数据先按name,再按id 进行排序。数据将按 name等于Philip J. Fry条件进行筛选。可以通过 Store 的 API 设置这些信息。

关联-Associations

实体可以通过关联 API 实现链接。大多数的应用需要处理很多不同的实体,而且这些实体之间经常具有一定的关联关系。一个博客的应用可能包括 User 和 Post 实体,每个 User 发表多个 Post。在这个示例中,一个用户有多个博文,每个博文只有一个用户。这就是通常所说的多对一的关系(ManyToOne)。我们可以这样表示它们之间的关系:

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',
        // the entityName for MyApp.model.User
        reference: 'User', 
        type: 'int'
    }, {
        name: 'title',
        type: 'string'
    }]
});

在应用中,很容易在不同的实体之间建立丰富的关联关系。每个实体可以与其他实体有多个关系。此外,实体可以任意的顺序定义。一旦你获得一个实体的数据,便可以获取其关联的数据。例如:你想获取一个用户的所有博文,可以这样处理:

// Loads User with ID 1 and related 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'));
            });
        });
    }
});

上述的关联关系,会自动为实体添加一个方法。一个 User 有多个 Post,将为 User 实体添加 posts() 方法,调用 user.posts() 方法将返回配置为 Post 实体模型的 Store?

关联不仅有助于加载数据,而且对于创建一条新的数据记录也很有帮助:

user.posts().add({
    userId: 1,
    title: 'Post 10'
});

user.posts().sync();

上述示例新建一个 Post,自动设置关联 User 的 id 属性为 userId 。 调用 sync() 方法将通过 schema 定义的代理保存新建的 Post 数据 。这是异步操作,如果想要获取操作是否完成的通知信息,可以传递一个回调函数。

反过来,该关联关系也为 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() 方法只是简单地设置 userId (有时称作外键)并保存 Post 实体数据。与其他方法一样,也可以传递一个回调函数,不论保存操作是否成功都将触发该函数。

加载嵌套数据-Loading Nested Data

当定义了实体间的关联关系,可以通过一次请求即可加载实体及其关联实体的数据。服务器端的响应可以像下述示例一样:

{
    "success": true,
    "user": [{
        "id": 1,
        "name": "Philip J. Fry",
        "posts": [{
            "title": "Post 1"
        },{
            "title": "Post 2"
        },{
            "title": "Post 3"
        }]
    }]
}

对于上述的响应结果,框架能够自动解析嵌套的数据。不必针对每个用户再单独请求Post数据,可以通过一次请求返回所有的数据。

验证-Validations

实体模型提供一套数据验证的支持。结合上述的示例演示一下。首先为 User 实体添加一些验证:

Ext.define('MyApp.model.User', {
    extend: 'Ext.data.Model',
    fields: ...,

    validators: {
        name: [
            'presence',
            { type: 'length', min: 7 },
            { type: 'exclusion', list: ['Bender'] }
        ]
    }
});

实体验证是以一个对象的方式定义的,字段的名称是要验证字段的规则名称。验证规则是以规则对象或规则数组的方式定义。示例演示的是name字段的验证规则,至少7个字符,并且不能是Bender。一些验证规则有多个配置选项,例如:长度验证规则可以配置minmax选项,格式化可以配置matcher等。Ext JS 有5个内置的验证规则,也可以创建自定义的验证规则。

内置的验证规则如下:

  • Presence - 字段值不可以为空。0是有效值,空字符串不是。
  • Length - 字段值长度介于 minmax 之间。两个约束是可选配置。
  • Format - 字符串必须符合一个正则表达式regular expression。在上述示例中可以定义一个规则,验证age字段只允许包含数字。
  • Inclusion - 字段值必须是给定的可选值,例如:性别必须是 male 或者 female
  • Exclusion - 字段值不能是给定范围的值,例如:用户名不能是黑名单内的值('admin')。

我们基本掌握了不同的验证规则,来试试如何使用它。创建一个用户,然后进行验证:

  // now lets try to create a new user with as many validation
  // errors as we can
  var newUser = new MyApp.model.User({
      id: 10,
      name: 'Bender'
  });

  // run some validation on the new user we just created
  console.log('Is User valid?', newUser.isValid());

  //returns 'false' as there were validation errors

  var errors = newUser.getValidation(),
      error  = errors.get('name');

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

这里的重点功能是 getValidation(),其执行所有配置的验证规则,返回一个对象。 对于不符合验证规则的字段返回不符合的第一个规则的错误信息,对于符合规则的字段返回true。该对象是延迟创建的对象,只有在请求该对象时才更新。

在上述示例中,name字段的第一个错误信息是:"Length must be greater than 7"。再试一下名称字段大于7个字符的情况:

newUser.set('name', 'Bender Bending Rodriguez');
errors = newUser.getValidation();

这时用户记录符合了所有的验证规则。newUser.isValid()将返回 true。当调用getValidation()方法时,验证结果对象将被更新,所有字段的验证结果都是 true

results matching ""

    No results matching ""