您的位置:首页 > Web前端 > JavaScript

Ext JS Data Package

2016-08-19 17:57 375 查看
Data package让我们可以在我们的代码或者application中加载和保存数据。最重要的一点是,data package可以让我们链接或者绑定数据到Ext JS组件。data apckage是由多个类组成,其中最重要的三个类为

Ext.data.Model

Store

Ext.data.proxy.Proxy

每个application差不多都会使用上面的三个类, 它们受到很多卫星类(围绕它们)的支持, 如下图所示



Ajax

在学习data package 之前,我们需要知道如何向服务器发送Ajax请求。

Ext JS提供了一个单例的对像Ext.Ajax, 我们可以通过它,向服务器发送请求

Ext.Ajax.request({
url:"serverside/myfirstdata.json"
});
console.log("Next lines of code...");


以上的请求是异步的,它不会阻止下一行代码的执行,你也可以运行同步的Ajax请求
Ext.Aajx.async = false


更多Ajax的配置可以查看http://docs.sencha.com/extjs/6.0.2-classic/Ext.Ajax.html#cfg-async

在上面的代码中,我没有处理服务器响应,我们需要在ajax配置中,配置一个callback函数, 这个函数在服务器响应时执行,同时还有 success or failure。

Ext.Ajax.request({
url:"serverside/myfirstdata.json",
success: function(response,options){
console.log('success function executed, here we can do some
stuff !');
},
failure: function(response,options){
Ext.Msg.alert("Message", 'server-side failure with status code
' + response.status);
},
callback: function( options, success, response ){
console.log('Callback executed, we can do some stuff !');
}
});


output

success function executed, here we can do some stuff !
Callback executed, we can do some stuff !


success会在服务器响应状态为200-299时执行,表示请求成功。如果响应为403, 404, 500, 503, 则执行failure方法。

success or failure都会接收两个参数,第一个参数是服务器响应对像, 通过它可以获得响应文本和响应头。第二个参数是我们对发起的Ajax请求的配置。在我们的例子中,options为URL, success, failure三个属性组成。

callback 函数将会一直执行,而不管是failure或者success. 并且这个函数接受三个参数: options 是请求时的配置, success是一个布尔值,如果请求成功,则为true, 否则为false. response参数是一个XMLHttpRequest对像,包含了响应的信息。

假设我们获得的响应为

{
"success": true,
"msg": "This is a success message..!"
}


对于success 来说, 响应返回的是纯文本的数据,我们需要将它解码为JSON数据

success: function(response,options){
var data = Ext.decode(response.responseText);
Ext.Msg.alert("Message", data.msg);
},


或者

callback: function( options, success, response ){
if(success){
var data= Ext.decode(response.responseText);
Ext.Msg.alert("Message", data.msg);
}
}


如果我们请求的是一个xml资源,而不是JSON

<?xml version="1.0" encoding="UTF-8"?>
<response success="true">
<msg>This is a success message in XML format</msg>
</response>


则代码为

Ext.Ajax.request({
url:"myfirstdata.xml",
success: function(response,options){
var data = response.responseXML;
var node = data.getElementsByTagName("msg")[0];
Ext.Msg.alert("Message", node.firstChild.data);
},
failure: function(response,options){
Ext.Msg.alert("Message", 'server-side failure with status code  ' + response.status);
},
callback: function( options, success, response ){
console.log('Callback executed, we can do some stuff !');
}
});


Passing parameters to Ajax request

为了相应的信息,我们需要向Ajax请求中传递需要的参数,我们将使用以下的代码来传递参数

//myfirstparams.php
<?php
header('Content-Type:application/json');
$output = array(
"msg"=> "Message response text using the following params:<br> x=" . $_POST["x"] . ", y=" . $_POST["y"]
);
echo json_encode($output);

//index.html

Ext.Ajax.request({
url:"myfirstparams.php",
method: "POST", //默认为GET
params: {
x: 200,
y: 300,
},
success: function(response,options){ var data = Ext.decode(response.responseText); Ext.Msg.alert("Message", data.msg); },
failure: function(response,options){
Ext.Msg.alert("Message", 'server-side failure with status code ' + response.status);
},
callback: function( options, success, response ){
console.log('Callback executed, we can do some stuff !');
}
});


Setting timeout to Ajax request calls

有时,服务器可能会长时间没有反应, 而Ext JS 默认等待响应的时间为30秒。根据需要,我们可以设置等待请求的时间

Ext.Ajax.request({
url: "serverside/myfirstparams.php",
method: 'POST',
params: {x:200, y:300},
timeout: 50000,
success: function(response,options){ var data = Ext.decode(response.responseText); Ext.Msg.alert("Message", data.msg); },
failure: function(response,options){
Ext.Msg.alert("Message", 'server-side failure with status code
' + response.status);
Ext.Msg.alert("Message", 'server-side failure:' +
response.status);
}
});


现在我们知道如何获取数据,但我们还需要一种方法来处理数据。 Ext JS为我们提供了一个简单的方法来管理数据。

Models

Ext.data.Model是data package的核心。在application中, 模型表示一个实体。比如一个电子商务的app, 可能会有Users, Products, Orders等模型。简单的讲,一个模型就是定义了一组字段,以及相关的业务逻辑。

以下是构成模型的几个部分

Fields 数据的名称,类型和值

Proxies 用来persist data或pull data

Validations 检验数据的有效性

Associations 与其它model的关系



Creating a Model

在创建一个model时,最好先创建一个公共的基础类。这个basic class允许我们配置所有model类的公共部分,比如它的id以及id字段的类型,同时,schema也在这个类中配置。schema用来管理所有的model, 相当于mysql中的schema数据库,而每个model相当于一张表。这个基础类如下所示

Ext.Ajax.request({
url: "serverside/myfirstparams.php",
method: 'POST',
params: {x:200, y:300},
timeout: 50000,
success: function(response,options){ var data = Ext.decode(response.responseText); Ext.Msg.alert("Message", data.msg); },
failure: function(response,options){
Ext.Msg.alert("Message", 'server-side failure with status code
' + response.status);
Ext.Msg.alert("Message", 'server-side failure:' +
response.status);
}
});


上面我们讲解了base model的重要性,接下来看看如何一步步的创建一个model

Ext.define('Myapp.model.Client',{
extend:'Ext.data.Model', // step 1
idProperty:'clientId ', // step 2
fields:[// step 3
{name: 'clientId', type: 'int'},
{name: 'name' , type: 'string'},
{name: 'phone' , type: 'string'},
{name: 'website' , type: 'string'},
{name: 'status' , type: 'string'},
{name: 'clientSince', type: 'date', dateFormat:'Y-m-d H:i'}
]
});


在第一步,我们让它继承于Ext.data.Model. 这类为所有的model提供了所有的功能。

第二步定义的属性每一条记录的ID, 在这里,我们使用的是clientId字段,如果我们在fields中没有定义clientId, model将会自动为我们默认产生一个id属性。

在第三步,我们为我们的模型定义了字段,这个属性是一个数组,数组中的每一个元素是一个对像,它包含了对每一个字段的配置。 在这里,我们只是设置了字段的名字和类型,在最后一个字段中,我们设置了一个dateFormat属性。

字段的更多配置可以查看Ext.data.field文档

数据的类型,包含以下几中

String

Integer

Float

Boolean

Date (使用此类型时,记得使用dateFormat属性,以确保解析正确的日期值)

Auto (表示对接受到的数据,不进行转换)

根据定义的model,我们创建一个数据

var myclient = Ext.create('Myapp.model.Client',{
clientId:10001,
name:'Acme corp',
phone:'+52-01-55-4444-3210',
website:'www.acmecorp.com',
status:'Active',
clientSince:'2010-01-01 14:35'
});
console.log(myclient);
console.log("My client's name is = " + myclient.data.name);
console.log("My client's website is = " + myclient.data.name);


创建完一条数据记录后,我们可以使用get和set方法,读写这个记录每个字段的值

// GET METHODS
var nameClient = myclient.get('name');
var websiteClient = myclient.get('website');
console.log("My client's info= " + nameClient + " - " +
websiteClient);
// SET Methods
myclient.set('phone','+52-01-55-0001-8888'); // single value
console.log("My client's new phone is = " +
myclient.get('phone'));
myclient.set({ //Multiple values
name: 'Acme Corp of AMERICA LTD.',
website:'www.acmecorp.net'
});
console.log("My client's name changed to = " +  myclient.get("name"));
console.log("My client's website changed to = " +  myclient.get("website") );


设置方法可以是单个的值,也是传递一个对像,同时设置多个值

其实所有的数据都是保存存在data属性上,我们应该使用get 和 set方法来读写数据,但因为某些原因,我们需要访问所有的数据时,我们可以使用这个data对像

//READ
console.log("My client's name:" + myclient.data.name);
console.log("My client's website:" + myclient.data.website);
// Write
myclient.data.name = "Acme Corp ASIA LTD.";
myclient.data.website = "www.acmecorp.biz";


虽然可以通过这种方法设置,但这不是最佳实践,因为能过setting方法设置时,会执行更多的任务,比如,标识我们的模型为脏数据,保存上一个值,在此之后,我们可以拒绝或者接收改变,还有一个其它的重要步骤。

Mappings

当在model中定义了一个字段,我们可以为这个字段定义一个mapping属性,告诉字个字段从哪获取数据。

{
"success" :"true",
"id":"id",
"records":[
{
"id": 10001,
"name": "Acme corp2",
"phone": "+52-01-55-4444-3210",
"x0001":"acme_file.pdf"
}
]
}


比如上面有一个”x0001”的字段,可以它在client模型中的名称为contractFileName, 所以我们需要使用mapping属性。

Ext.define('Myapp.model.Client',{
extend: 'Ext.data.Model',
idProperty: 'clientId ',
fields:[
{name: 'clientId', type: 'int' },
{name: 'name' , type: 'string'},
{name: 'phone' , type: 'string'},
{name: 'contractFileName', type: 'string', mapping:'x0001'}
]
});


Validations

从Ext JS 4开始,可以直接在model中对数据进行验证。

Ext.define('MyApp.model.User', {
extend: 'Ext.data.Model',
fields: ...,
validators: {
name: [  //需要校验的字段
'presence',
{ type: 'length', min: 7 },
{ type: 'exclusion', list: ['Bender'] }
]
}
});


Validators是一个对像,这个对像的每个键对应于要检验的字段名。每个字段的检验规则,可以为一个对像配置,或者这些配置组成的数组。在这个例子中,我们是验证name字段,它的长度为7个字符以上,它的值不能为 “Bender”.

有的验证规则,接收额外的配置 - 比如 length校验器,可以有min 和 max属性。 format 可以一个matcher等等。 以下是Ext JS内置的检验器,并且还可以自定义规则

Presence - 保证这个字段必须有值,空字符串无效

Length - 保证字符串的长度在min和max之前。min 和 max这两个约束条件是可选的

Format - 保证字符串匹配一个正则表达式format.

Inclusion - 保证一个值必须在指定的列表中,比如,gender只能为 male或者 female

Exclusion - 保证一个值不能出现在指定的列表中

更多的检验器,可以查看Ext.data.validator空间下的子类, 了解如何传递参数, 比如Presence, http://docs.sencha.com/extjs/6.0.2-classic/Ext.data.validator.Presence.html

接下来,让我们创建一个违返这些规则的一条记录

/ 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(), 它运行所有的检验规则,但只返回每一个字段,第一条没有通过的规则。这些检验记录是被懒性创建,只在需要的时候才会更新。在这里,错误为Length must be greater than 7.

当我们提供的名字超过规定的长度时

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


这条记录符合所有的检验,它包含7个字符,同时也不跟列表中的Bender匹配。

newUser.isValid()将会返回true, 当我们调用getValidation(), 新的检验记录将被更新,数据不在是脏数据。它所有的字段都将设置为true.

以下是另一个例子

Ext.define('Myapp.model.Client',{
extend:'Ext.data.Model',
idProperty:'clientId ',
fields:[
{name: 'clientId', type: 'int' },
{name: 'name' , type: 'string'},
{name: 'phone' , type: 'string'},
{name: 'website' , type: 'string'},
{name: 'status' , type: 'string'},
{name: 'clientSince' , type: 'date', dateFormat: 'Y-m-d H:i'}
],
validators:{
name:[
{ type:'presence'}
],
website:[
{ type:'presence', allowEmpty:true},
{ type:'length', min: 5, max:250 }
]
}
});

//Step 1
var myclient = Ext.create('Myapp.model.Client',{
clientId : '10001',
name : 'Acme corp',
phone: '+52-01-55-4444-3210',
website: 'www.acmecorp.com',
status: 'Active',
clientSince: '2010-01-01 14:35'
});

if (myclient.isValid()){ //Step 2
console.log("myclient model is correct");
}
console.log(myclient);
console.log("My client's name is = " + myclient.data.name);
console.log("My client's website is = " + myclient.data.website);
// SET methods //Step 3
myclient.set('name','');
myclient.set('website','');
if (myclient.isValid()){//Step 4
console.log("myclient model is correct");
} else {
//Step 5
console.log("myclient model has errors");
var errors = myclient.validate();
errors.each(function(error){
console.log(error.field,error.message);
});
}


在第5步,我们使用了validate方法,它将返回一个验证失败的集合。并且输出字段以及错误信息. 这个集合的类型为Ext.data.ErrorCollection, 它扩展于Ext.util.MixedCollection. 因此我们可以使用each方法来遍历每一条错误记录.



Custom field types

在我们的application中不同的model之前,经常需要反复使用某个字段类型,在 Ext JS 4在,我们可以通过自动义检验器实现。 但在Ext JS 5开始,推荐使用自定义字段类型来代替自定义检验器。能过以下代码,我们将创建一个自定义字段

Ext.define('Myapp.fields.Status',{
extend: 'Ext.data.field.String', //Step 1
alias: 'data.field.status',//Step 2
validators: {//Step 3
type: 'inclusion',
list: [ 'Active', 'Inactive'],
message: 'Is not a valid status value, please select the
proper options[Active, Inactive]'
}
});


继承于Ext.data.field.String

我们为这个字段类型,定义了一个别名。这个别名不能重复,或者说覆盖一个已经存在于Ext.data.field中的子类

为这个字段类型设置校验器

Ext.define('Myapp.model.Client',{
extend:'Ext.data.Model',
idProperty:'clientId ',
fields:[
{name: 'clientId', type: 'int' },
{name: 'name' , type: 'string'},
{name: 'phone' , type: 'string'},
{name: 'website' , type: 'string'},
{name: 'status' , type: 'status'}, //Using custom field
{name: 'clientSince' , type: 'date', dateFormat: 'Y-m-d H:i'}
],
validators:{
...
}
});


在这里,我们使用的是
{name: 'status', type: 'status'}
, 这是因为我们给自定义类型,取了一个别名(alias: ‘data.field.status’). 下面让我们创建一段代码来测试

var myclient = Ext.create('Myapp.model.Client',{
clientId: '10001',
name: 'Acme corp',
phone: '+52-01-55-4444-3210',
website: 'www.acmecorp.com',
status: 'Active',
clientSince: '2010-01-01 14:35'
});
if(myclient.isValid()){
console.log("myclient model is correct");
}
// SET methods
myclient.set('status','No longer client');
if(myclient.isValid()){
console.log("myclient model is correct");
} else {
console.log("myclient model has errors");
var errors = myclient.validate();
errors.each(function(error){
console.log(error.field,error.message);
});
}


Relationships

我们可以创建模型之间的关系。比如,一个Client会接触多名employees, 享受多种Service.

Employees for contact(Client联系的员工, 包含name, title, gender, email, phone, cell phone, 等字段)

Services (service ID, service name, service price, branch where service provided)

在Ext JS中支持one-to-many, one-to-one, and many-to-many关联

关于更多Association Type,可以查看http://docs.sencha.com/extjs/6.2.0-classic/Ext.data.schema.Association.html

One-to-many associations

Ext.define('Myapp.model.Client',{
extend:'Ext.data.Model', // step 1
requires: ['Myapp.model.Employee'],
idProperty:'id ',
fields:[.... ],
hasMany:{
model:'Myapp.model.Employee',
name:'employees',
associationKey: 'employees'
}
});


使用了hasManay属性,我们定义了一个one-to-many的关系。hasMany属性可以是一个对像数组,每一个对像都包含一个model属性. 表明一个Client实例,可以有多个 Myapp.model.Employee对像。

此外,我们可以在创建Client类时,定义获得与它相关联model数据的函数名称。在这里,我们使用employees; 如果我们没有定义任何的函数名称, Ext JS将使用子模型的名字,加上”s”, 作为函数名称

现在我们创建一个Employee类,它位于appcode/model/Employee.js

Ext.define('Myapp.model.Employee',{
extend:'Ext.data.Model',
idProperty:'id ',
fields:[
{name: 'id', type: 'int' },
{name: 'clientid' , type: 'int'},
{name: 'name' , type: 'string'},
{name: 'phone' , type: 'string'},
{name: 'email' , type: 'string'},
{name: 'gender' , type: 'string'}
]
});


为了测试model之前的关系,我们创建以下代码

var myclient = Ext.create('Myapp.model.ClientWithContacts',{
id: 10001,
name: 'Acme corp',
phone: '+52-01-55-4444-3210',
website: 'www.acmecorp.com',
status: 'Active',
clientSince: '2010-01-01 14:35'
});
//Step 2
myclient.employees().add(
{
id:101, clientId:10001, name:'Juan Perez', phone:'+52-05-2222-333',
email:'juan@test.com', gender:'male'},
{
id:102, clientId:10001, name:'Sonia Sanchez', phone:
'+52-05-1111-444', email:'sonia@test.com',gender:'female'}
);
//Step 3
myclient.employees().each(function(record){
console.log(record.get('name') + ' - ' + record.get('email') );
});


我们创建一个Client的记录

我们执行employees方法,这个方法是在定义关联类时,指定的name属性。这个方法返回一个Ext.data.Store实例。它是一个集合,用来管理相应的模型。所以我们可以通过它的add方法,添加两个Employee对像。

我们遍历myclient中的employees集合。每个记录表示一个Employee对像,所以我们可以使用get方法,获得它每个字段的值

One-to-one associations

为了描述这种关系,我们创建了一个合同类,来与 Client相关联

Ext.define('Myapp.model.Contract',{
extend:'Ext.data.Model',
idProperty:'id ',
fields:[
{name: 'id', type: 'int' },
{name: 'contractId', type: 'string'},
{name: 'documentType', type: 'string'}
]
});


如果你所看到的,这是一个正常的类。现在我们来定义Customer类

Ext.define('Myapp.model.Customer',{
extend:'Ext.data.Model',
requires: ['Myapp.model.Contract'],
idProperty:'id ',
fields:[
{name: 'id', type: 'int'},
{name: 'name' , type: 'string'},
{name: 'phone' , type: 'string'},
{name: 'website' , type: 'string'},
{name: 'status' , type: 'string'},
{name: 'clientSince' , type: 'date', dateFormat: 'Y-m-d H:i'},
{name: 'contractInfo' , reference: 'Contract', unique:true}
]
});


我们添加了一个字段,称为contractInfo, 但我们使用reference代替了type属性。它表示contractInfo的值为一个Contract类的实例。

var myclient = Ext.create('Myapp.model.Customer',{
id: 10001,
name: 'Acme corp',
phone: '+52-01-55-4444-3210',
website: 'www.acmecorp.com',
status: 'Active',
clientSince: '2010-01-01 14:35',
contractInfo:{
id:444,
contractId:'ct-001-444',
documentType:'PDF'
}
});


我们在这里是直接为contractInfo赋值一个对像. 如下所示



你看到上图中contractInfo是一个对像,它的字段跟Contract模型中定义的字段相同。如果contractInfo对像中没有定义Contract中的字段,则整个contractInfo则为undefined.



Exmaple

我们以一个博客应用为例,它有User和Post两个model. 每一个User都可以创建Post. 所以在这种情况下,一个user 可以有多个post. 但一个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',
reference: 'User', // the entityName for MyApp.model.User
type: 'int'
}, {
name: 'title',
type: 'string'
}]
});


通过以上面的方式,可以很容易的实现我们应用中不同Model之前的关系。每一个Model可以跟其它的Model产生关联。同时,模型定义的顺序可以是任意的。一旦,你创建了这个Model类型的记录, 通过这条记录,就可以遍历与之相关联的数据。如果你想要获得一个用户的所有post. 你可以通过以下的代码

// 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 model都有多个Posts, 它会被添加一个user.posts()函数,调用user.posts()返回一个Post model的Store集合.

不仅我们可以加载数据,还可以创建一条新的记录

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

user.posts().sync();


上面的代码会创建一个Post实例,并且自动赋值userId字段为用户的id. 调用sync(),通过post的代理,保存这个新的Post(schema的代理配置决定). 这是一个异步操作,如果你需要获得操作完成后的通知,可以给它传递一个回调函数。

相返的,在Post model中,也会生成一个新的方法

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(有时称为 “外键”)为100,并且保存Post model. 通常也可以传递一个回调函数,在保存操作完成后,触发回调函数,知道操作是否成功.

加载嵌套的数据

当定义了associations后,可以在单个请求中,加载相关联系的记录。比如, 一个服务器响应如下数据

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


框架可以自动解析这个当个响应中的嵌套数据。而不用创建两个请求。

Stores

一个store是某一个模型对像的集合(比如多个users集合,invoices集合),作为一个客户端缓存来管理我们本地的数据。我们可以使用这个集合执行多种任务,比如排序,分组, filtering. 我们也可以使用一个有效的proxies从服务器上拉数据,和一个render解析服务器响应,并且填充这个集合.

一个store经常被添加到widgets/componens,用来显示数据。比如组件中的grid, tree, combo box, 或者data view,都会使用一个store来管理数据。当我们创建一个自定义 widget,我们也应该使用一个store来管理数据。

为了创建一个store, 我们需要使用Ext.data.Store类。代码如下

Ext.define('MyApp.store.Customers',{
extend : 'Ext.data.Store', //Step 1
model : 'Myapp.model.Customer' //Step 2
});

//Ext JS 6的写法 http://docs.sencha.com/extjs/6.0.2-classic/guides/core_concepts/data_package.html 
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, 我们需要让它继承于Ext.data.Store, 这个类负责处理models.

我们需要为创建的store,关联一个模型。它必须为一个有效的model类。

当我们创建了一个store类后,可以使用这个store来存取数据

var store = Ext.create("MyApp.store.Customers");
//counting the elements in the store
console.log(store.count());


Adding new elements

我们可以创建一个Customer数据,并且通过add 或者insert方法,将这个新的元素添加到store.

//Step 1 (define /create new model instance)
var mynewcustomer = Ext.create('Myapp.model.Customer',{
id: 10001,
name: 'Acme corp',
phone: '+52-01-55-4444-3210',
website : 'www.acmecorp.com',
status: 'Active',
clientSince: '2010-01-01 14:35',
contractInfo:{
id:444,
contractId:'ct-001-444',
documentType:'PDF'
}
});
store.add(mynewcustomer); //Step 2
console.log("Records in store:" + store.getCount() );


也可以使用以下的方法

//Method 2 for add Records
store.add({
id: 10002,
name: 'Candy Store LTD',
phone: '+52-01-66-3333-3895',
website : 'www.candyworld.com',
status: 'Active',
clientSince: '2011-01-01 14:35',
contractInfo:{
id:9998,
contractId:'ct-001-9998',
documentType:'DOCX'
}
});
console.log("Records in store:" + store.getCount());


如果想一次添加多个,我们可以传递一个数组给 add方法。

// Method 3 for add multiple records
var mynewcustomer = Ext.create('Myapp.model.Customer', { ...});
var mynewcustomerb = Ext.create('Myapp.model.Customer', {
...});
store.add([mynewcustomer, mynewcustomerb]);
console.log("Records in store:" + store.getCount());


store使用add方法,会将新的元素添加到集合的最后位置,如果我们想添加一个元素到第一的位置,或才其它位置,则可以使用
insert
方法

Inline data

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"
}]
});


遍历store中的记录

store.each(function(record, index){
console.log(index, record.get("name"));
});


each方法接受一个函数。这个函数将被store中的每一条记录执行。这个匿名函数接收两个参数,每一次遍历时的record和index.

我们也可以给each方法传递第二个参数,表明这个匿名函数的作用域。

store中检索记录

通过位置索引

如果我们想获得指定位置的model, 我们可以使用getAt方法

var modelTest = store.getAt(2);
console.log(modelTest.get("name"));


First and last records

var first = store.first();
var last = store.last();
console.log(first.get("name"), last.get("name"));


* By range*

var list = store.getRange(1,3); //获取位置1开始的,3条记录,包含位1, 2, 3的记录
Ext.each(list,function(record,index){
console.log(index,record.get("name"));
});


By ID

var record = store.getById(10001);
console.log(modelTest.get("name"));


Removing records

我们有三种方法删除记录

store.remove(record);
store.each(function(record,index){
console.log(index,record.get("name"));
});


在上面的代码中,remove传递的参数是一个model引用。

我们也可以一次性删除多个记录。我们只需要把要删除的model数组传递给它

store.remove([first,last]);
store.each(function(record,index){
console.log(record.get("name"));
});


有时,我们没有model的引用,在这种情况下,我们可以通过记录的位置进行删除

store.removeAt(2);
store.each(function(record,index){
console.log(index,record.get("name"));
});


如果我们想要删除所有的记录, 我们仅需要调用removeAll方法.

store.removeAll();
console.log("Records:",store.count()); // Records: 0


Sorting and Grouping

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

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


Retrieving remote data

到目前为此,我们使用的都是本地数据,但在真实的应用中,我们的数据是保存在数据库当中的,或者需要通过web服务才能获取到数据。

Ext JS使用proxies发送和接收数据。proxies通常配置在store或者model。也可以像我们在最开始的base model代码,在schema中定义.

在Ext JS中Proxies负现处理model的数据,我们可以说proxy是一个处理和操作数据(parsing, organizing等等)的类. 所以store可以通过proxie来读取和保存,或者发送数据到服务器。

一个proxy使用一个reader来解码接收到的数据,使用一个writer将数据编码为正确的格式,并且发送到数据源。reader有Array, JSON, XML三种类型,而writer只有JSON, XML类型。

proxies主要分为两种类型, Client 和 Server,如果我们想要改变我们数据源,我们仅需要改变proxy类型,而其它的都不需要改变。比如,我们为store或model定义一个Ajax proxy, 然后我们可以将它设置为 local storage proxy.

Client Proxy

Memory

Local Storage

Server Proxy

AJAX

JSONP

REST

Ajax proxy

Ext.define('Myapp.store.customers.Customers',{
extend:'Ext.data.Store',
model: 'Myapp.model.Customer',
proxy:{
type:'ajax',
url: 'serverside/customers.php',
reader: {
type:'json',
rootProperty:'records' //json中的数据字段
}
}
});


之后我们就可以创建这个store, 并且从远程加载数据

//Step 1
var store = Ext.create("Myapp.store.customers.Customers");
//Step 2
store.load(function(records, operation, success) {
console.log('loaded records');//Step 3
Ext.each(records, function(record, index, records){
console.log( record.get("name") + ' - ' +
record.data.contractInfo.contractId );
});
});


在我们执行例子之前,我们应该在服务器上创建一个serverside/customers.json

{
"success":true,
"id":"id",
"records":[
{
"id": 10001,
"name": "Acme corp2",
"phone": "+52-01-55-4444-3210",
"website": "www.acmecorp.com",
"status": "Active",
"clientSince": "2010-01-01 14:35",
"contractInfo":{
"id":444,
"contractId":"ct-001-444",
"documentType":"PDF"
}
},{
"id": 10002,
"name": "Candy Store LTD",
"phone": "+52-01-66-3333-3895",
"website": "www.candyworld.com",
"status": "Active",
"clientSince": "2011-01-01 14:35",
"contractInfo":{
"id":9998,
"contractId":"ct-001-9998",
"documentType":"DOCX"
}
}
]
}


Readers

Readers让Ext JS知道如何处理响应.

如我们上面的例子

reader: {
type:'json',
rootProperty:'records'
}


type属性表示使用什么格式来解析。它可以为json, xml, array.

rootProperty允许我们定义一个在服务器响应中的属性名字,服务器返回的数据都是这个字段下。在JSON响应中,它可以为一个数组。 在我们的例子中,我们设为records, 因为我们的JSON使用的是这个名字。如果我们嵌套的是一个对像,可以使用如下的方式

{
"success" :"true",
"id":"id",
"output":{
"appRecords":[{ our data .... }],
"customerRecords":[{ our data .... }]
}
}


reader: {
type:'json',
rootProperty:'output.customerRecords'
}


XML reader

XML reader相对于JSON来说有些变化,因此,我们需要在这个render中,配置其它属性, 以确保XML可以正常解析

proxy:{
type:'ajax',
url: 'serverside/customers.xml',
reader: {
type: 'xml',
rootProperty: 'data',
record:'customer',
totalProperty: 'total',
successProperty: 'success'
}
}


rootProperty 定义了 XML文件中查找records的节点。

我们还添加了一个record属性,在XML中每一个记录的名称

totalProperty和successProperty, store有的功能需要使用到这个标签下的值

现在,让我们创建一个XML文件 serverside/customers.xml

<?xml version="1.0" encoding="UTF-8"?>
<data>
<success>true</success>
<total>2</total>
<customer>
<id>10001</id>
<name>Acme corp2</name>
<phone>+52-01-55-4444-3210</phone>
<website>www.acmecorp.com</website>
<status>Active</status>
<clientSince>2010-01-01 14:35</clientSince>
<contractInfo>
<id>444</id>
<contractId>ct-001-444</contractId>
<documentType>PDF</documentType>
</contractInfo>
</customer>
<customer>
<id>10002</id>
<name>Candy Store LTD</name>
<phone>+52-01-66-3333-3895</phone>
<website>www.candyworld.com</website>
<status>Active</status>
<clientSince>2011-01-01 14:35</clientSince>
<contractInfo>
<id>9998</id>
<contractId>ct-001-9998</contractId>
<documentType>DOCX</documentType>
</contractInfo>
</customer>
</data>


Sending data

Ext.define('Myapp.store.customers.CustomersSending',{
extend:'Ext.data.Store',
model: 'Myapp.model.Customer',
autoLoad:false,
autoSync:true,
proxy:{
type:'ajax',
url: 'serverside/customers.json',
api: {
read : 'serverside/customers.json',
create : 'serverside/process.php?action=new',
update : 'serverside/process.php?action=update',
destroy : 'serverside/process.php?action=destroy'
},
reader: { type:'json', rootProperty:'records' },
writer:{
type:'json',
encode:true,
rootProperty:'paramProcess',
allowSingle:false,
writeAllFields:true,
root:'records'
},
actionMethods:{
create: 'POST',
read: 'GET',
update: 'POST',
destroy: 'POST'
}
}
});


设置了一个api 属性: 为CRUD分别设置一个url

设置一个writer属性

type: ‘json’: 以JSON格式发送数据

encode: 表示在传递数据到服务器前,是否经过Ext JS进行编码

rootProperty: 包信息的属性的名字

writeAllFields: 传递所有的记录到服务器,如果为false, 则只发送个改的字段。

对CRUD所对应的方法类型

Ext.Loader.setConfig({
enabled: true,
paths:{ Myapp:'appcode' }
});
Ext.require([
'Ext.data.*',
'Myapp.model.Contract',
'Myapp.model.Customer',
'Myapp.store.customers.CustomersSending'
]);
Ext.onReady(function(){
var store = Ext.create("Myapp.store.customers.CustomersSending");
//Step 1
store.load({ // Step 2 load Store in order to get all records
scope: this,
callback: function(records, operation, success) {
console.log('loaded records');
Ext.each(records, function(record, index, records){
console.log( record.get("name") + ' - ' +
record.data.contractInfo.contractId );
});
var test=11;
console.log('Start adding model / record...!');
// step 3 Add a record
var mynewCustomer = Ext.create('Myapp.model.Customer',{
clientId : '10003',
name: 'American Notebooks Corp',
phone: '+52-01-55-3333-2200',
website : 'www.notebooksdemo.com',
status : 'Active',
clientSince: '2015-06-01 10:35',
contractInfo:{
"id":99990,
"contractId":"ct-00301-99990",
"documentType":"DOC"
}
});
//因为我们设置了autoSync属性为true,所以会发送数据到服务器
store.add(mynewCustomer);
// step 4 update a record
console.log('Updating model / record...!');
var updateCustomerModel = store.getAt(0);
updateCustomerModel.beginEdit();
updateCustomerModel.set("website","www.acmecorpusa.com");
updateCustomerModel.set("phone","+52-01-33-9999-3000");
updateCustomerModel.endEdit();
// step 5 delete a record
console.log('deleting a model / record ...!');
var deleteCustomerModel = store.getAt(1);
store.remove(deleteCustomerModel);
}
});
});
});


Schema

介绍

一个Schema是相关Ext.data.Model和之前关系Ext.data.schema.Association的集合。

Schema Instances

默认情况下这个类以单例创建,作为模式服务于所有的实体(model中没有明确指明schema配置, 也没有继承schema配置)

当一个entity指定了一个schema, 相关联的类,就能够查找(or create)这个entity类的实例,然后继承这个实例。

Importnat: 所有相关的entities 必须属性单个schema实例,这样才能正确的连接它们的关联性。

Configuring Schemas

控制schema配置的最好方式是定义一个 base model

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}'
}
}
}
});


通过使用base class, 你所有的model类在声明创建时,都已要有拥有schema中的默认配置。

Relative Naming

当描述两个model之前的关系时,需要使用简单的名称,它不包含共同的namespace部分. 它称为entityName, 而不是类名称。 默认情况下, entityName是整个类的名称。但是,如果使用了namespace属性时,共同的部分会被丢弃, 我们可以得到简单的名称。
MyApp.model.Foo
entityName
Foo
.
MyApp.model.foo.Thing
foo.Thing


Association Naming

在描述关系时,有不同的术语。最能说明阐明这些术语的一个简单例子是,User与 Group这种多对多的关系

entityName - “User”和”Group”为
entityName
, 它们都是从完整的类名中简写获得(App.model.User and App.model.Group)

associationName - 当我们谈论关系时,特别是many-to-many. 给它们命名就非常重要。Associations(关联)不被涉级的任何一个实体拥有, 所以这时,这个名称就类似于一个entityName. 默认的associationName为”GroupUsers”.

left and right - Association(关联)描述了两个实例之前的关系。在谈论具体的关系时,我们可以使用两个参与者的entityName(比如User or Group). 当谈论一个抽像的associations

比如”GroupUsers”这个关系,”User”称为 left, 而”Group”称为right. 在一个many-to-many的关联时, 我们可以任意的选择left和right. 当涉及到外键时,left 则是被包含的外键

Custom Naming Conventions

Schema的一个工作就是管理名字的生成(比如entityName). 这个工作它是委派给namer类。 如果你需要以其它的方法生成名字,你可以为你的定提供自定义的namer

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

schema: {
namespace: 'MyApp.model',
namer: 'custom'
}
});


类似于alias创建一个类,如下所示

Ext.define('MyApp.model.CustomNamer', {
extend: 'Ext.data.schema.Namer',
alias: 'namer.custom',
...
});
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  ext data ajax model