ExtJS4.1 Data Package

来源:互联网 发布:增删算法统宗 编辑:程序博客网 时间:2024/05/07 07:01

数据(Data)

所谓数据包,它是用来装载和保存程序中的数据,并且组成41个类。其中 Model、Store和 Ext.data.proxy.Proxy是最重要的三个;它们几乎会在每一个应用中都被应用到,并且被一系列的卫星类(satellite classes)支持:


模型(Models)和存储(Stores)

数据包的核心就是 Ext.data.Model。Model用来表示程序中的数据类型,例如:一个电子商务系统会有Users模型、Products模型和Orders模型等。简单来说,模型(Model)就是一系列字段和字段值的集合。我们来看看比较重要的四种模型 — Fields、Proxies、 Associations 和Validations。


来看一下如何创建一个新的Model:

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

Model通常结合Store一起使用,总体来说,Store就是一系列实例Model的集合。建立一个Store并且加载数据都比较简单:

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

以上配置是通过Ajax代理(Ajax Proxy)来获取数据的,这里需要指定数据加载地址(url)和 Reader (用来解析数据)。本例中,由于服务器返回的是JSON,所以reader配置为“json”( Json Reader )来读取返回的数据。Store会自动从user.json这个地址加载数据,从user.json返回的JSON数据格式应该如下:

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

点击 Simple Store 亲手试一试。

内联数据(Inline data)

Store也可以加载内联数据。其实在本质上,Store是将我们传递给它的数据最终都转换成了Model实例:

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

亲手试一试

排序和分组(Sorting and Grouping)

Store可以在本地执行排序、过滤和分组操作,当然也支持远程的排序、过滤和分组:

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

在我们刚刚创建的store中,数据将会首先按照name进行排序,然后按照id进行排序;过滤器会将name值为Ed的User给过滤出来;然后数据还会按照age进行降序分组。详情请参见API文档

试一试

代理(Proxies)

Store通过代理(Proxy)来加载和保存数据模型。代理分为两种:客户端代理和服务端代理。像浏览器内存储和HTML本地化都是客户端代理的例子。服务端代理处理远程服务器的数据封装,例如:Ajax、JsonP和Reset。

代理可以直接定义在一个模型里面:

Ext.define('User', {    extend: 'Ext.data.Model',    fields: ['id', 'name', 'age', 'gender'],    proxy: {        type: 'rest',        url : 'data/users',        reader: {            type: 'json',            root: 'users'        }    }});// 使用用户模型代理Ext.create('Ext.data.Store', {    model: 'User'});

这给我们带来了两点好处。首先,极有可能每个使用到user模型的Store都会以相同的方式来加载数据,这样就避免了为每个Store重复定义代理(Proxy)。其次,我们可以无需通过Store进行加载和保存数据。

// 获取一个User类的引用var User = Ext.ModelMgr.getModel('User');var ed = Ext.create('User', {    name: 'Ed Spencer',    age : 25});// 我们可以直接保存Ed,而不是必须首先将其添加到Store,这是由于我们配置了RestProxy,它会自动向/users这个地址发送POST请求ed.save({    success: function(ed) {        console.log("Saved Ed! His ID is "+ ed.getId());    }});// 加载User 1并执行相关操作 (向 /users/1发起GET请求)User.load(1, {    success: function(user) {        console.log("Loaded user 1: " + user.get('name'));    }});

Proxy也受益于HTML5的新功能- LocalStorage 和SessionStorage。尽管老版本的浏览器不支持HTML5的API,但它们确实是十分有用的,许多应用将极大的受益于他们。

尝试一下

关联(Associations)

多个Model可以通过Assocaition API联系在一起。绝大部门的应用都会处理许多不同的Model,而这些Model通常都是有联系的。例如一个博客应用程序中会有User、Post和Comment这些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' }});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'});

可以很容易地表达您的应用程序中的不同Models之间的丰富关系。每个Model可以与其他Model有任意数量的关联(Associations),Model可以按照任何的顺序定义。一旦我们有一个Model的实例,我们可以很容易地遍历相关的数据 - 例如,如果我们想对指定用户的每篇文章的所有评论作记录,就可以这样做: 

// Loads User with ID 1 and related posts and comments using User's ProxyUser.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关联都会产生一个新的函数添加到Model中。我们定义User model hasMany Posts,会新增user.posts()函数供我们在上面的代码片段使用。调用guser.posts()返回Post model的 Store配置。反过来,Post model获取comments() 函数是因为我们设置的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字段会自动填充上用户ID。调用sync()通过其配置的Proxy保存新Post - 这又是一个异步操作。如果你想操作完成时发送通知,也可以添加一个回调函数(callback)。

belongsTo关联也可以生成新的Model方法,可以这样使用这些方法: 

// get the user reference from the post's belongsTo associationpost.getUser(function(user) {    console.log('Just got the user reference from the post: ' + user.get('name'))});// try to change the post's 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)是异步的,需要一个回调函数来获取用户实例。setUser方法只需更新foreign_key(这里是user_id)为100并保存Post model。通常情况下,无论成功与否,都可以在完成保存操作的时候触发回调函数

加载嵌套数据(Loading Nested Data)

你也许会奇怪,为什么我们发送一个成功函数到User.load的调用,但在访问用户的文章和评论时却没有这样做。这是因为上面的例子中假定,当我们提出请求获取一个用户,服务器返回的用户数据会嵌套所有的文章和评论。通过设立像上面那样的关联,框架可以自动解析出嵌套在单一请求中的数据。框架不是先获取用户数据,然后调用另一个请求获取文章数据,然后再发出更多的请求获取评论,而是在一个服务器响应里返回所有数据:

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

数据全部是框架自动分析的。可以很容易地配置Model的代理来加载任何地方的数据,用他们的Reader来处理几乎任何返回格式(的数据)。至于Ext JS3,整个框架的许多组件都用到了Model和Store,如Grids、Trees 和Forms。

尝试一下

当然,可以用非嵌套的方式来加载数据。如果你需要“延迟加载(只有被需要的时候才会加载)”,这就会有用了。我们来像以前那样加载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'));                    });                });            }        });    }});

尝试一下

验证(Validations)

Ext JS 4的数据验证变得丰富了许多。为了证明这一点,我们要用上述关联的例子。首先,让我们为User模型添加一些验证(validations):

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(性别)字段要么是“male”要么是“female”,username可以是除了“admin”的任何东西。某些验证还会采取额外的可选配置 - 例如长度验证可以采取Min和Max属性,格式可以用正则表达式等等。Ext JS的内置验证总共有5个,添加自定义的规则也很容易。首先,让我们看看内置验证:

  •  presence 确保该字段有一个值。计数0有效,但是空字符串无效。 
  •  length 确保一个字符串在最小(min)和最大(max)长度之间。这两种约束(min和max)是可选的. 
  •  format 确保一个字符串匹配一个正则表达式格式。在上面的例子中,我们确保年龄字段是由数字组成的。 
  •  inclusion 确保值是特定的值(例如确保性别是男性或女性)。 
  •  exclusion 确保不是某值(例如列入黑名单的username,像是“admin”)。

到目前位置,我们已经掌握了不同验证的用处,让我们尝试在用户实例中使用它们。我们将创建一个用户,并针对它运行验证,并指出任何错误:

// now lets try to create a new user with as many validation errors as we canvar newUser = Ext.create('User', {    name: 'admin',    age: 'twenty-nine',    gender: 'not a valid gender'});// run some validation on the new user we just createdvar errors = newUser.validate();console.log('Is User valid?', errors.isValid()); //returns 'false' as there were validation errorsconsole.log('All Errors:', errors.items); //returns the array of all errors found on this model instanceconsole.log('Age Errors:', errors.getByField('age')); //returns the errors for the age field

这里的主要是validate()方法,它运行所有配置过的验证,并返回一个错误对象(Errors object)。这个简单的对象仅仅是一个被我们发现的所有错误的集合,还有一些方便的方法:比如isValid(),如果任何字段都没有错误就返回true;  getByField(),它返回一个给定字段中的所有错误。

尝试一下

原创粉丝点击