Extjs4 API文档阅读(四)——Data

来源:互联网 发布:sql server 注释 编辑:程序博客网 时间:2024/06/01 22:37

上一节,我们介绍了下布局及容器,本节本来要介绍下组件,但是组件方面的资料暂时没有翻译完成,所以本节先介绍下数据(Data)。

数据

Data包负责加载和保存你应用程序中的所有数据,由41个类构成,其中有三个类是最重要的,分别是模型类(Model),存储类(Store),代理类(Ext.data.proxy.Proxy)。它们几乎在每个应用程序中都被使用到,并且很多相附类为它们提供支持。

模型类和存储类

模型类(Ext.data.Model)data包的核心部件。每个模型代表应用程序中的一些数据类型-例如一个电子商务应用程序可以有UsersProductsOrders等模型类。简单来说,模型仅仅是一些域和每个域对应数据的集合。我们将重点研究模型类中的四个主要部分(Fields)、代理(Proxies)、关联(Associations)和验证(Validations)

现在让我们看看如何创建一个模型类:

 
Ext.define('User', {    extend: 'Ext.data.Model',    fields: [        { name: 'id', type: 'int' },        { name: 'name', type: 'string' }    ]});

模型类通常在存储类中使用,这些存储类主要是一些模型实例的集合。设置存储类和加载它的数据是简单的:

 
Ext.create('Ext.data.Store', {    model: 'User',    proxy: {        type: 'ajax',        url : 'users.json',        reader: 'json'    },    autoLoad: true});

我们用Ajax代理( Ajax Proxy)配置我们的存储类,告诉它加载数据的url地址和用来解码数据的读取器(Reader)。这样,我们的服务器将返回JSON格式的数据,我们可以使用设置的Json读取器(Json Reader)解析响应。上面创建的存储类实例从url地址users.json中自动加载一系列User模型类实例的数据。

users.json应该返回如下所示的JSON字符串:

 
{    success: true,    users: [        { id: 1, name: 'Ed' },        { id: 2, name: 'Tommy' }    ]}

请查看Simple Store获取一个演示实例。

内联数据

存储类实例也可以加载内联数据,它们转换每个传递进data中的对象为模型类实例:

 
Ext.create('Ext.data.Store', {    model: 'User',    data: [        { firstName: 'Ed',    lastName: 'Spencer' },        { firstName: 'Tommy', lastName: 'Maintz' },        { firstName: 'Aaron', lastName: 'Conran' },        { firstName: 'Jamie', lastName: 'Avins' }    ]});

内联数据的例子(Inline Data example)

排序和分组

存储类实例能在本地执行排序、过滤和分组,同样也提供远程排序、过滤和分组:

 
Ext.create('Ext.data.Store', {    model: 'User',    sorters: ['name', 'id'],    filters: {        property: 'name',        value   : 'Ed'    },    groupField: 'age',    groupDir: 'DESC'});

我们刚刚创建的存储类实例中,数据首先将按照name排序,其次按id排序;并且数据将被过滤为仅包含nameEdUsers,然后数据将按年龄进行分组且遵循由小到大的顺序。任何时候调用存储类API进行排序、过滤和分组都是是很轻松的。查看排序、分组、过滤存储类实例(Sorting Grouping Filtering Store获取一个演示示例。

代理

代理类被存储类使用以便于管理加载和保存模型类数据。有两种类型的代理:客户端代理(Client)和服务器端代理(Server)客户端代理包括存储数据在浏览器内存的内存方式(Memory)和使用HTML5本地存储器(可用时)的本地存储方式(Local Storage)。服务器端代理操作一些从远程服务器调度来的数据,例如包括AjaxJsonpRest方式。

代理方式可以直接在模型类中定义,如下:

 
Ext.define('User', {    extend: 'Ext.data.Model',    fields: ['id', 'name', 'age', 'gender'],    proxy: {        type: 'rest',        url : 'data/users',        reader: {            type: 'json',            root: 'users'        }    }}); // Uses the User Model's ProxyExt.create('Ext.data.Store', {    model: 'User'});

这对我们有两方面的好处:首先,使得每个使用User模型类的存储类实例以相同方式加载数据变得可行,这样我们避免了必须为每个存储类实例复制相同代理方式定义。其次,现在我们可以不使用存储类来加载和保存模型数据:

 
// Gives us a reference to the User class// 创建一个User类的引用var User = Ext.ModelMgr.getModel('User');var ed = Ext.create('User', {    name: 'Ed Spencer',    age : 25});// We can save Ed directly without having to add him to a Store first because we//我们可以直接保存ed而不用先把它添加到一个存储类中,因为我们配置了// configured a RestProxy this will automatically send a POST request to the url /users//一个能自动发送一个POST请求到指定url的Rest代理ed.save({    success: function(ed) {        console.log("Saved Ed! His ID is "+ ed.getId());    }}); // Load User 1 and do something with it (performs a GET request to /users/1)//加载User 1并对其一些相关操作(执行一个GET请求到 /users/1)User.load(1, {    success: function(user) {        console.log("Loaded user 1: " + user.get('name'));    }});

也有利用HTML5新功能-- LocalStorage SessionStorage的代理模式。尽管旧的浏览器不支持这些新的HTML5 APIs,它们仍然是有用的,因为很多应用程序将从这些新特性的存在中受益。

直接在模型类中使用代理的例子(Example of a Model that uses a Proxy directly)

关联

模型类之间可以通过关联API链接在一起。大多数应用程序需要处理很多不同的模型类,并且这些模型类之间通常是相关联的。例如一个博客写作应用程序可能有User(用户)Post(文章)Comment(评论)等模型类。每个用户(User)可以创建多篇文章(Posts),并且每篇文章接受很多评论(Comments)。我们可以如下表示这些关系:

 
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' }}); 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: { model: 'Comment', name: 'comments' }});Ext.define('Comment', {    extend: 'Ext.data.Model',    fields: ['id', 'post_id', 'name', 'message'],    belongsTo: 'Post'});

使得在你的应用程序中表示这种复杂关系变得简单。 每个模型类可以和其他模型类有任意的关联,并且你的模型类可以按任意顺序定义。一旦我们创建了一个模型类实例,我们可以很轻松地遍历与其相关联的数据--例如,如果我们想记录一个给定用户每篇文章的所有相关评论,我们可以如下这样操作

 
// Loads User with ID 1 and related posts and comments using User's Proxy//加载User使用ID 1和相关的文章和评论使用User的代理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'));            });        });    }});

例我们创建每一个的hasMany关联将产生一个新方法添加到这个模型类上。我们声明的每个User模型类实例有许多(hasMany)文章(Posts),这将为我们添加user.posts()方法,如上面代码段中使用的那样。调用user.posts()方法返回一个配置了Post模型的存储类实例。依次类推,Post模型实例获取了一个comments()方法,因为我们为其设置了hasMany评论关联。关联不仅对加载数据来说是有用的,而且对创建新记录也是有用的

 
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();

这里我们实例化了一个新Post模型类,该实例将自动把User中的id赋值给Post中的user_id字段。调用sync()方法,将通过配置的代理方式来保存新创建Post模型类实例再者,如果你想让操作完成时得到反馈,你可以调用异步操作并传递进一个回调函数来实现。属于(belongsTo)关联也能在模型类实例生成一个新方法,如我们下面介绍的这个示例:

 
// get the user reference from the post's belongsTo association//得到user实例引用从post实例的belongsTo关联配置post.getUser(function(user) {    console.log('Just got the user reference from the post: ' + user.get('name'))});// try to change the post's user//尝试改变文章的userpost.setUser(100, {    callback: function(product, operation) {        if (operation.wasSuccessful()) {            console.log('Post\'s user was updated');        } else {            console.log('Post\'s user could not be updated');        }    }});

再次说明,加载函数(getUser)是异步调用的,并且需要一个回调函数作为参数来获得user实例。setUser方法仅更新外键(本例中的user_id字段)的值为100,并保存这个Post模型类实例。通常,不管成功与否,当保存操作完成时,传递进去的回调函数都将被触发。

加载内嵌的数据

你或许想知道为什么调用User.load方法时,我们传递一个success方法,但当访问User的文章(Post)及评论(Comment)时我们并不需要这样做。这是因为上面的例子中,我们假定当发送请求获取一个用户信息时,服务器返回了该用户的数据及所有嵌套的文章和评论数据。上例我们通过设置关联配置,框架在一次请求中就能自动解析出嵌套的数据。不是先发送一个请求获取用户数据,另一个请求获取文章数据,再发送其他请求以获取每篇文章的评论数据这种模式,我们可以在一次服务器响应中返回所有的数据,如下:

 
{    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'                        }                    ]                }            ]        }    ]}

这些数据将被框架自动解析出来。配置模型类的代理方式以用来加载任何地方的数据会变得很轻松,并且它们的阅读器模式几乎可以处理任何格式的响应数据Ext JS 3一样,模型类和存储类在整个框架中被许多组件使用,例如表格,树,表单。

查看关联和验证(Associations and Validations)的演示例以获取一个实际操作并且具有关联关系的模型实例

当然,你可以以一种非嵌套的方式加载你的数据。如果你仅想需要时加载相关的数据,这种懒惰加载模式将可能是有效地。前所做,我们仅加载User数据,除此之外,我们假定返回的响应仅包含User数据,没有任何关联的文章(Post)数据。然后,我们在user.posts().load()方法添加回调函数中以获取相关的文章(Post)数据:

 
// Loads User with ID 1 User's ProxyUser.load(1, {    success: function(user) {        console.log("User: " + user.get('name'));        // Loads posts for user 1 using Post's Proxy        user.posts().load({            callback: function(posts, operation) {                Ext.each(posts, function(post) {                    console.log("Comments for post: " + post.get('title'));                    post.comments().each(function(comment) {                        console.log(comment.get('message'));                    });                });            }        });    }});

查看懒惰关联(Lazy Associations)模式可以获取一个完整的示例

验证

Ext JS 4起,模型类由于提供了验证数据的功能而变得更加丰富精彩了。为了证明这点,我们将在前面使用过的关联例子的基础上构建一个示例。首先让我们添加一些验证到User模型类中:

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

验证和域定义遵循相同的代码格式。任何情况下,我们都可以指定一个域和一种验证类型。我们例子中的验证器配置要求name域必须存在,并且至少5个字符长,age域必须为数字,gender域的值只能为malefemale,并且用户名可以为除了admin外的其他任何名称。一些验证器可能具有其他的可选配置--例如,长度验证可以具有最大和最小属性,格式(format)具有匹配(matcher)属性等。Ext JS有五种内置的验证器,且可以轻松地添加用户自定义规则。首先让我们看看这五种类型:

  • 存在(presence)  确保该域必须有确定值。0被看作有效值,但空字符串将被视为有效值。
  • 长度(length)  确保一个字符串长度位于最大和最小值之间。两个参数都是可选的。
  • 格式(format)  确保一个字符串匹配指定的正则表达式。上例中我们确保age域必须为数字。
  • 包含(inclusion) 确保该域的值在指定的数值集合中(例如确保性别只能是男或女)。
  • 排除(exclusion) 确保该域的值不在指定的数值集合中(例如用户名不能为admin

既然我们已经理解了不同验证器的功能,让我们尝试在一个User实例中使用它们。

我们创建一个user实例并在其中运行验证器,注意产生的任何错误:

 
// now lets try to create a new user with as many validation errors as we can// 现在让我们尝试创建一个user实例,并产生尽量多的验证错误var newUser = Ext.create('User', {    name: 'admin',    age: 'twenty-nine',    gender: 'not a valid gender'});

// run some validation on the new user we just created

// 在我们刚刚创建的user实例中运行一些验证器

var errors = newUser.validate();

console.log('Is User valid?', errors.isValid());//returns 'false' as there were validation errors当有验证器错误产生时,返回false

console.log('All Errors:', errors.items);//returns the array of all errors found on this model instance返回该模型类实例所有错误组合成的数组

console.log('Age Errors:', errors.getByField('age'));//returns the errors for the age field返回age域产生的错误

这里的关键函数是validate(),该函数运行所有配置验证器并返回一个Errors对象。这个简单的对象为所有错误的集合,并且添加了一些便利的方法,例如isValid()--当任何域都没有错误产生时,返回true,还有getByField()法,返回给定域产生的所有错误。

请查看关联和验证(Associations and Validations)示例以获取一个使用验证器的复杂例子。

本文由本站网友听雨(QQ:448447268)进行翻译,请尊重劳动成功,转载及复制本文信息,请注明来源:http://www.mhzg.net及作者名称。