Ember.js 概念详解--模型
来源:互联网 发布:财汇金融数据库 编辑:程序博客网 时间:2024/05/18 00:10
此文中讲到的ember-data已经是老版本,不推荐大家使用了。
由于是从word考过来的,格式不是太好,大家可以直接去下载我的完整word。里面除了翻译还有原创内容。
http://download.csdn.net/detail/kevinwon1985/5230326
在大多数Ember应用中,模型都通过Ember Data处理。Ember Data是一个专门用于框架的库。它设计目的是方便的从个服务端获取数据,在浏览器中改变数据,并将改变保存回服务器。
它提供了很多能在服务端找到的管理ORM的工具,例如活动记录。但是它是专门为了浏览器环境中的javascript设计的。
在遵循某些惯例的情况下,不需要很多配置,Ember Data通过RESTful JSON API能加载数据,保存数据和关系。
3.3.1 定义Store
每个使用Ember Data的应用都需要有store。Store负责保存已经加载的记录和接收还没加载的记录。
你会与模型直接交互,而不是store。然后,你需要告诉框架你想使用Ember Data管理你的模型。所以,你需要定义一个DS.Store的子类。
App.Store = DS.Store.extend({
revision: 11
});
注意这里定义的revision。它是Ember Data API版本号,被Ember Data用来通知你更新。升级了Ember Data后,这个数字会改。它也会在Ember Data的版本到达1.0的时候被移除。
如果你想使用自己的连接器,来代替默认的DS.RESTAdapter。这样写:
App.Store = DS.Store.extend({
revision: 11,
adapter:'App.MyCustomAdapter'
});
3.3.2 定义模型
3.3.2.1 属性
App.Person = DS.Model.extend({
firstName: DS.attr('string'),
lastName: DS.attr('string'),
birthday: DS.attr('date'),
fullName:function() {
returnthis.get('firstName') + '' +this.get('lastName');
}.property('firstName','lastName')
});
默认的REST连接器中,支持的属性类型有string,number,boolean,和date。自定义的连接器可以提供额外的属性类型,新属性可以注册为transforms。详见3.3.6。
3.3.2.2 关系
Ember Data 包含数种内置关系类型来帮助你定义模型间的关系。
单对单
App.User = DS.Model.extend({
profile: DS.belongsTo('App.Profile')
});
App.Profile = DS.Model.extend({
user: DS.belongsTo('App.User')
});
单对多
App.Post = DS.Model.extend({
comments: DS.hasMany('App.Comment')
});
App.Comment = DS.Model.extend({
post: DS.belongsTo('App.Post')
});
多对多
App.Post = DS.Model.extend({
tags: DS.hasMany('App.Tag')
});
App.Tag = DS.Model.extend({
posts: DS.hasMany('App.Post')
});
3.3.3 查找记录
3.3.3.1. 返回一条记录
通过传递唯一的id来查找一条记录用find方法。
var post = App.Post.find(1);
如果查找的记录已经存在于本地,就会立即返回。这个特性,我们有时叫它身份映射。
否则,会创建一条新的记录,并设置它的状态为loading,然后返回。此时马上就可以在模版中使用这条记录了。因为框架中所有的所有东西都是绑定好的,模版会在这条记录加载完成后自动更新。
3.3.3.2. 查找所有记录
你也可以用使用无参数的find方法查找所有的记录。
var post = App.Post.find();
这会返回一个DS.RecordArray的实例。这个recordArray开始是loading状态,length是0,但是你可以在模版中马上用它,像用一个列表一样。当服务端响应并返回结果,模版会自动更新。
注意:DS.RecordArray不是一个Javascript数组,它是一个实现了Ember.Enumerable的对象。如果你想要通过索引访问它的成员,需要用objectAt(index)方法,用[index]是不会起作用的。
3.3.3.3. 检索
你可以通过传递一个hash对象来使用find方法来向服务器检索。
var people = App.Person.find({ name: "Peter" });
这个hash对象的具体内容框架并不知道,需要由服务器来解析,并且返回一个模型实例集合集。
3.3.4 修改属性
只有在一条记录已经加载,你才能修改它的属性。就像修改一个Ember对象一样。
var tyrion = App.Person.find(1);
// ...after the record has loaded
tyrion.set('firstName',"Yollo");
所有框架的便捷修改属性的方法都可以用。例如Ember.Object的incrementProperty。
person.incrementProperty('age');
你可以通过检测记录的isDirty属性来判断这条记录的改动是否已经保存。
person.get('isDirty');
//=> false
person.set('isAdmin', true);
person.get('isDirty');
//=> true
确保记录已经加载,再去修改它的属性。如果在loading状态修改,Ember Data会抛异常。
3.3.5 模型生命周期
DS.Model的实例都有一组布尔值的属性来判断记录的当前状态。• isLoaded 连接器已经从后台取回了记录。
• isDirty 在本地修改了记录但是还没通过连接器保存。这也包括新建和删除的记录。
• isSaving 连接器已经向后台发送了保存的请求,但是还没确认保存成功。
• isDeleted 记录被标记为删除。当isDeleted为true,isDirty也为true,该记录只是在本地被删除,服务端还没删除。当isSaving为true,删除请求在发送中。当isDirty和isSaving都是false,改变已经被保存。
• isError 连接器表示不能将本地修改保存到后台。当连接器收到服务端的验证失败通知时,这也可能导致isValid属性变为false。
• isNew 记录已经在本地被创建,但是还没有被连接器成功保存。
• isValid 客户端验证通过,并且连接器没有收到服务端验证失败的通知。
另外,记录状态改变时会产生一些可以被监听的事件。
record.on('didLoad',function() {
console.log("Loaded!");
});
有以下事件:
• didLoad
• didCreate
• didUpdate
• didDelete
• becameError
• becameInvalid
记录的状态:
• Loading
还没有从服务端接收到属性值和关系。一条记录通常以loading状态开始。
试图修改loading状态的记录会导致一个异常。
• Loaded/clean
同时处于Loaded和clean两个状态意思是,已经从个服务端接收到了属性值和关系,并且本地没有对记录进行任何修改。
• Dirty
记录已经在本地被改变,但是还没有与服务端同步。
• In-flight
dirty状态的记录已经发起了与服务端的同步请求。一旦服务端保存成功,记录状态会被置为clean。
• Invalid
服务端返回通知数据验证不通过而不能保存。
• Error
服务端由于某些不正当的理由而没有保存。
3.3.6 REST
连接器Ember Data默认使用DS.RESTAdapter加载和保存记录。REST连接器假定URL和模型关联的JSON都是按惯例的。如是遵循了那些规则,就不需要配置任何东西。
3.3.6.1. URL约定
连接器基于模型的名字自动生成通讯的URL。例如,通过ID查找User的一条记录var user = App.User.find(1);
REST连接器会自动发送一个GET请求到/users/1。
在REST连接器中,你可以对记录进行的操作映射成下面的URL
操作
HTTP method
URL
Find
GET
/users/1
Find All
GET
/users
Update
PUT
/users/1
Create
POST
/users
Delete
DELETE
/users/1
3.3.6.1.1. 复数配置
不规则的复数可以通过连接器的configureAPI指定
DS.RESTAdapter.configure("plurals", {
person:"people"
});
这会告诉连接器
App.Person请求的地址会由/persons/1变成/people/1。3.3.6.1.2. 路径配置
可以通过url和namespace来配置请求的路劲。默认请求地址是url+namespace+上面的操作地址。
DS.RESTAdapter.reopen({
url:'https://api.example.com',//默认是“”
namespace: 'api/1' //默认是undefined
});
为App.Person请求的地
。3.3.6.2. JSON格式约定
当像后台请求数据,REST连接器期望返回的JSON数据符合以下约定
3.3.6.2.1. JSON ROOT
如果你从/people/123请求一条记录,返回的记录要内嵌在person属性中。
{
"person": {
"first_name":"Jeff",
"last_name":"Atwood"
}
}
3.3.6.2.2. 属性名用下划线连接符
属性名的多个单词需要使用下划线连接。例如,有如下模型
App.Person = DS.Model.extend({
firstName: DS.attr('string'),
lastName: DS.attr('string'),
isPersonOfTheYear: DS.attr('boolean')
});
isPersonOfTheYear的驼峰格式要用下划线代替。返回一条记录的JSON是这样的
{
"person": {
"first_name":"Barack",
"last_name":"Obama",
"is_person_of_the_year": true
}
}
不规则的属性名可以通过连接器的map方法进行映射。
App.Person = DS.Model.extend({
lastName: DS.attr('string')
});
'App.Person', {lastName: {key:'lastNameOfPerson' }
});
3.3.6.2.3. 关系
引用到其他记录要通过id。例如,你有一个hasMany关系的模型。
App.Post = DS.Model.extend({
comments: DS.hasMany('App.Comment')
});
返回的JSON需要编码关系为一个ids的数组
{
"post": {
"comment_ids": [1, 2, 3]
}
}
post的comments可以通过post.get('comments')加载。REST连接器会发送GET请求到/comments?ids[]=1&ids[]=2&ids[]=3。
所有belongsTo关系,在JSON中都用模型名字加_id。例如:你有这样一个模型
App.Comment = DS.Model.extend({
post: DS.belongsTo('App.Post')
});
返回的JSON是这样的
3.3.6.2.4. 偏载关系
为了减少请求数,你可以在返回的JSON中偏载额外的记录。偏载的记录在JSON ROOT之外,并且是一个hash数组。
{
"post": {
"id": 1,
"title":"Rails is omakase",
"comment_ids": [1, 2, 3]
},
"comments": [{
"id": 1,
"body":"But is it _lightweight_ omakase?"
},
{
"id": 2,
"body":"I for one welcome our new omakase overlords"
},
{
"id": 3,
"body":"Put me on the fast track to a delicious dinner"
}]
}
3.3.6.2.5. 自定义属性类型
一些情况下,内置的属性类型string, number, boolean, 和 date不够用。例如,服务器返回非标准的日期格式。
Ember的连接器都可以自定义属性类型:
DS.RESTAdapter.registerTransform('coordinatePoint', {
serialize:function(value) {
return [value.get('x'), value.get('y')];
},
deserialize:function(value) {
return Ember.create({x: value[0],y: value[1] });
}
});
App.Cursor = DS.Model.extend({
position: DS.attr('coordinatePoint')
});
position返回的是一个数组
{
cursor: {
position: [4,9]
}
}
但是加载后,它是一个对象:
var cursor = App.Cursor.find(1);
cursor.get('position.x');//=> 4
cursor.get('position.y');//=> 9
- Ember.js 概念详解--模型
- Ember.js 概念详解--路由器
- Ember.js 指引--核心概念
- ember.js
- Ember.js 入门指南——定义模型
- Ember学习(1):Ember核心概念
- PowerDesigner 概念模型详解
- PowerDesigner概念模型详解
- PowerDesigner概念模型详解
- PowerDesigner概念模型详解
- PowerDesigner概念模型详解
- PowerDesigner概念模型详解
- MVC、MVP、MVVM、Angular.js、Knockout.js、Backbone.js、React.js、Ember.js、Avalon.js、Vue.js 概念摘录
- MVC、MVP、MVVM、Angular.js、Knockout.js、Backbone.js、React.js、Ember.js、Avalon.js、Vue.js 概念摘录
- Ember.js常用函数
- ember.js教程
- Ember.js学习总结
- Ember.js实战
- 讲师秀之7:林仕鼎谈架构设计与架构师
- ubuntu下查看当前网络流量工具
- 翻译《The rsync algorithm》
- Android Audio System 之一:AudioTrack如何与AudioFlinger交换音频数据
- 冒泡排序、选择排序、插入排序的比较
- Ember.js 概念详解--模型
- 基于dedup技术的远程相似文件同步
- Struts 2整合Spring
- python 学习笔记(11)XML文件
- Android Audio System 之二:AudioFlinger
- Column-oriented database
- 企业即时通讯软件2013 即时通讯大手笔
- Adler32算法的实现
- struct dirent的char d_name[1]成员