Ext JS 4:模型剖析
如果你在跟踪Ext JS动态,你可能已经知道,在Ext JS 4中有一个全新的数据包。新的数据包在Ext JS 3的基础上,增加了大良的新功能。近期我们在博客上介绍了新的数据包,今天我们将深度探讨新的Model类。
几乎每一个Model类就代表了应用程序中持久化的数据类型。例如,在电子商务应用程序可能包含用户、产品、订单等模型,而每个模型包含一些字段以及允许应用操作这些数据的函数。例如,一个订单模型可以包含一个“shipToCustomer”的函数用来实现配送流程。
Ext JS 3.x之前的版本有一个Record类,它与Model类非常类似。所不同的是,Record类虽然也包含字段和函数,但Model类功能更强大。今天,我们将介绍Model类的死个主要功能:字段、代理、关系和验证。
字段
每个模型都由一个或多个字段组成。简单来说,一个字段就是一个名字,如“id”、“email”和“phone”是用户模型的字段。它们可以有一个类型(int、float、string或auto),甚至可以有一个转换函数用来编辑它们的值。例如,用户的身高,我们可以通过一个函数将它从英寸转换为厘米。
下面代码演示了如何建立一个只有3个字段的简单用户模型。在第一个字段中,我们将其类型设置为“int”,意味着它应该是一个整数。在第二个字段中,我们将不指定类型,这以为着它将使用“auto”作为默认类型。“auto”类型表示接受任何传递给它的数据。在第三个字段中,虽然我们也将它设置为“int”类型,但我们提供了一个转换函数用来将英寸值转换为厘米值。
1 | Ext . regModel ( ' User ' , { |
2 | fields : [ |
3 | { name : ' id ' , type : ' int ' } , |
4 | ' name ' , |
5 | { |
6 | name : ' height ' , |
7 | type : ' int ' , |
8 | convert : function ( inches ) { |
9 | return Math . round ( inches * 2 . 54 ) ; |
10 | } |
11 | } |
12 | ] |
13 | } ) ; |
现在我们可以很简单的创建一个用户实例来观察字段定义如何影响到他们的数据:
1 | var abe = new User ( { |
2 | id : 123 , |
3 | name : ' Abe Elias ' , |
4 | height : 76 |
5 | } ) ; |
6 | |
7 | console . log ( abe . get ( ' id ' ) ) ; // logs 123 (a JavaScript Number object) |
8 | console . log ( abe . get ( ' name ' ) ) ; // logs 'Abe Elias' (A JavaScript String object) |
9 | console . log ( abe . get ( ' height ' ) ) ; // logs 193 (inches converted to centimeters) |
使用模型的简单实例非常简单,但是,一个应用程序通常需要加载或保存大量数据,因此,我们需要使用到代理。
代理
在Ext JS 4中,代理可以从不同的数据源加载或保存数据。譬如,可以使用Ajax,也可以使用HTML5的localStorage,或保存在内存中的数据。在Ext JS 4中定义了一系列在默认情况下使用的代理,你也可以根据需要,轻松的创建自己的代理。让我们看看,如何在用户模型中建立代理:
1 | Ext . regModel ( ' User ' , { |
2 | fields : [ ' id ' , ' name ' , ' email ' ] , |
3 | |
4 | proxy : { |
5 | type : ' rest ' , |
6 | url : ' / users ' , |
7 | reader : ' json ' |
8 | } |
9 | } ) ; |
直接在模型中定义代理是Ext JS 4的新功能,这意味着我们可以不用象Ext JS 3那样,需要创建一个Store,就可以很轻松的加载或保存数据。
在上面的代码中,用户模型使用了RestProxy代理,它将使用AJAX从服务器中加载或保存数据。它会根据提供的基本地址自动的构建RESTful地址(上面例子的是“/users”)。我们也可以创建一个使用JsonReader的代理,在用户模型实例中处理服务器响应和解码数据。在这种情况下,我们知道服务器将返回JSON数据,因此需要使用JsonReader。
让我们来加载一个用户模型:
1 | // GET /users/123 |
2 | User . load ( 123 , { |
3 | success : function ( user ) { |
4 | console . log ( user . get ( ' name ' ) ) ; |
5 | } |
6 | } ) ; |
上面的代码将从地址“/user/123”加载数据,这是根据我们将id传递给User.load函数构造出来的地址。接着,JsonReader将响应的数据解码到用户对象。服务器返回的数据格式如下(使用的是上面log实例的代码):
1 | // response from GET /users/123 |
2 | { |
3 | " id " : 123 , |
4 | " name " : " Aaron Conran " , |
5 | " email " : " aaron@sencha.com " |
6 | } |
不要轻易满足,我们将介绍更高等级的数据关联。
关系
在一个应用中通常都会有多个模型,而且他们都不是单独存在的。在模型之间都会存在关联,例如,系统中的用户都会有订单,而每个订单又是由订单项组成。Ext JS 4为我们提供了简单而直观的API,从而使我们可以在客户端表现这些关系。让我们创建以下3个模型:
1 | // each User hasMany Orders |
2 | Ext . regModel ( ' User ' , { |
3 | fields : [ ' id ' , ' name ' , ' email ' ] , |
4 | proxy : { |
5 | type : ' rest ' , |
6 | url : ' / users ' , |
7 | reader : ' json ' |
8 | } , |
9 | |
10 | hasMany : ' Orders ' |
11 | } ) ; |
12 | |
13 | // each Order belongsTo a User, and hasMany OrderItems |
14 | Ext . regModel ( ' Order ' , { |
15 | fields : [ ' id ' , ' user_id ' , ' status ' ] , |
16 | belongsTo : ' User ' , |
17 | hasMany : ' OrderItems ' |
18 | } ) ; |
19 | |
20 | // each OrderItem belongsTo an Order |
21 | Ext . regModel ( ' OrderItem ' , { |
22 | fields : [ ' id ' , ' order_id ' , ' name ' , ' description ' , ' price ' , ' quantity ' ] , |
23 | belongsTo : ' Order ' |
24 | } ) ; |
现在,应用程序已经知道相关模型及其关系,下面看看我们如何使用它们。现在我们扩展一下上面代理一节的例子,让我们服务器响应的数据格式如下:
1 | { |
2 | " id " : 123 , |
3 | " name " : " Aaron Conran " , |
4 | " email " : " aaron@sencha.com " , |
5 | " orders " : [ |
6 | { |
7 | " id " : 1 , |
8 | " status " : " shipped " , |
9 | " orderItems " : [ |
10 | { |
11 | " id " : 2 , |
12 | " name " : " Sencha Touch " , |
13 | " description " : " The first HTML5 mobile framework " , |
14 | " price " : 0 , |
15 | " quantity " : 1 |
16 | } |
17 | ] |
18 | } |
19 | ] |
20 | } |
当我们加载用户数据时,相关的订单和订单项数据会与它一起加载,这样就能使我们的代码实现互动:
1 | User . load ( 123 , { |
2 | success : function ( user ) { |
3 | console . log ( user . get ( ' name ' ) ) ; // "Aaron Conran" |
4 | console . log ( user . orders ( ) . getCount ( ) ) ; // "1" -- there is only 1 order in the response above |
5 | |
6 | // we can iterate over the orders easily using the Associations API |
7 | user . orders ( ) . each ( function ( order ) { |
8 | console . log ( order . get ( ' status ' ) ) ; // "shipped" |
9 | |
10 | // we can even iterate over each Order's OrderItems: |
11 | order . orderItems ( ) . each ( function ( orderItem ) { |
12 | console . log ( orderItem . get ( ' title ' ) ) ; // "Sencha Touch" |
13 | } ) ; |
14 | } ) ; |
15 | } |
16 | } ) ; |
关系API是Ext JS 4中最强大的功能之一。因为Sencha Touch的数据包和Ext JS 4是相同的,因为你可以下载Sencha Touch并查看与HasMany或 Belongs的相关API文档。
验证
今天我们要介绍的最后一个共嫩是验证。在Ext JS 3,只有在表单中才可以进行验证。但在上面的实例代码中,我们操纵的数据都不需要表单,因此我们需要在模型级别进行验证。幸运的是,Ext JS已经支持这一点,让我们来看看:
1 | Ext . regModel ( ' User ' , { |
2 | fields : [ ' id ' , ' name ' , ' email ' , ' height ' ] , |
3 | |
4 | validations : [ |
5 | { type : ' presence ' , field : ' id ' } , |
6 | { type : ' length ' , field : ' name ' , min : 2 } , |
7 | { type : ' format ' , field : ' email ' , matcher : / [ a - z ] @ [ a - z ] . com / } |
8 | ] |
9 | } ) ; |
在上面代码中,我们在用户模型设置了3个简单的验证。首先,“id”字段被设置为必须是存在的;然后,“name”字段的长度至少需要2个字符;最后,我们使用正则表达式验证“emali”字段。
我们可以通过这些验证确保模型的数据是正确。在下面代码,我们将创建一个没有“id”,用户名也不是有效数据的用户,并要求它进行验证:
1 | var ed = new User ( { |
2 | email : " ed@sencha.com " |
3 | } ) ; |
4 | |
5 | var validation = ed . validate ( ) ; |
6 | |
7 | console . log ( validation . isValid ( ) ) ; // false |
8 | |
9 | // we can easily output or manipulate any validation errors |
10 | validation . each ( function ( error ) { |
11 | console . log ( error . field + " " + error . message ) ; |
12 | } ) ; |
13 | |
14 | // in this case, the output looks like this: |
15 | " id must be present " |
16 | " name is the wrong length " |
了解更多
我们们已经了解了新的模型类的四大基石:字段、代理、关系和验证。掌握好这4个概念可以让你使用Ext JS 4或Sencha Touch创建更好的应用程序。要了解更多数据包的信息,可以看看我们最近的博客文章或者阅读Sencha Touch的文档。