文章泉源:http://xcoding.tech/tags/Emberjs
迎接接见源网站Ember Teach,Ember Teach致力于为您供应最威望、最前沿的Ember手艺教程。。
adapter与serializer相对来说是比较高等的内容。然则也是异常经常运用的一个组件,最经常运用到这两个组件的就是Ember Data。Ember Data已完成了这两个组件,而且供应了异常丰富的API,假如要自定义适配器和序列化器平常都是扩大或许是重写JSONAPIAdapter,这也是官方发起的体式格局,JSONAPIAdapter是遵照json api范例的适配器,主要表现在数据的交流花样必需遵照JSONAPI范例。固然假如你想完整从新完成一套自定义的适配器和序列化器也是能够的,官方发起是基于Adapter做扩大。由于才能有限本示例不会完整自定义适配器和序列化器,示例仍然是运用官方引荐体式格局,重写或许扩大JSONAPIAdapter以完成自定适配器和序列化器。
那末我们为什么须要自定义适配器呢?很明显的一个缘由就是Ember.js并没有供应数据存储计划,Ember现在更多的只是一个前端的MVC框架,数据的存储效劳照样要开辟者供应,现在比较盛行的做法是运用谷歌的Firebase,Firebase是一个及时更新数据的后端效劳,国内也有相似的跟随者(野狗)然则现在野狗还没有Ember的适配器,相反Firebase供应了完整的Ember适配器,运用起来异常轻易,而且还供应了免费的效劳。能够说除了网速比较慢以外是异常适合做Ember的数据效劳的。然则比较遗憾的是我们在天朝内,你懂滴,谷歌的东西在我们这个国家要运用照样不怎样顺畅的。那末既然不能运用现有的轮子那末我们只能运用自身的后端数据效劳了,此时就必须要自定义适配器了(我们能直接运用Firebase的缘由就是Firebase供应圆满的适配器,不须要开辟者去开辟,直接运用即可)。
Ember所推重是“商定由于设置”,一切Ember默许了许多划定规矩,天然适配器和序列化器也不破例,所以本例子顺序会包括两个方面的东西,一个是Ember项目自身;另一个是为Ember项目供应效劳器的后端数据库以及数据库处置惩罚顺序。
主要软件申明
上述软件的装置与设置请自行依据各自官网文档引见装置设置,假如你想运用其他数据库也是能够的,然则处置惩罚起来能够没有MongoDB那末轻易,假如你看过jsonapi范例就晓得,jsonapi相关于一般的json数据照样有挺大差异的,假如是运用其他数据库(比方MySQL)处置惩罚起来能够轻微贫苦一些,别的一个很主要的缘由就是json API插件大部分都是node版的,说了这么多实在就是想把效劳器返回的数据花样花样化为jsonapi范例,不然其他花样的数据JSONAPIAdapter适配器是没法辨认的,会报错。
再烦琐几句:一个APP之所以能与后端效劳优越交互,其他交互的数据花样都是比较牢固的,Ember也不破例,由于Ember Data所接收的数据花样是jsonapi,所以我们的后端效劳返回的数据花样必需相符jsonapi范例,固然假如你不是运用Ember Data,你运用的是其他的数据耐久化库也是能够的,那末相对的你的的后端数据效劳返回的数据花样就要跟你的耐久化库相匹配就能够了,假如你想运用其他的耐久化库你能够参考jsonapi client libraries,上面供应了各个言语的耐久化库。
搭建项目
言归正传,下面连系一个小例子解说怎样去自定义适配器去连接到自身的数据库,并把数据耐久化到数据库中。
运用Ember CLI建立一个一般的Ember项目,敕令以下:
ember new ember-adapter-serializer
cd ember-adapter-serializer
ember s
启动项目后预览http://localhost:4200,能够看到Ember通例的迎接信息,申明项目建立胜利。
建立路由、模子、模板
仍然是运用Ember CLI敕令建立演示示例所需的路由、模子、模板文件,本示例会构建一个简朴的博客项目,目标主如果为了使项目只管包括模子的一对一、一对多、多对多关联,这些关联是一个适配器比较症结的东西(简朴明白,实在适配器就像MVC项目中的DAO层,特地做数据处置惩罚的)。
建立敕令以下:
ember g route users
ember g model user
ember g route users/list
ember g route users/new
ember g route users/edit
ember g route posts
ember g model post
ember g route tags
ember g model tag
ember g route comments
ember g model comment
后续运用到其他的文件再建立。
模子处置惩罚
模子的处置惩罚主如果设置模子的属性以及模子之间的关联,在本例子中定义了3个模子:user
、post
、tag
、comment
。他们的关联以下:
- user与post是一对多的关联
- user与comment是一对多的关联
- post与comment也是一对多的关联
- post与tag是多对多关联
各个模子代码以下:
user
// app/models/user.js
import Model from 'ember-data/model';
import attr from 'ember-data/attr';
import { belongsTo,hasMany } from 'ember-data/relationships';
export default Model.extend({
name: attr('string'),
password: attr('string'),
birth: attr('string'),
addr: attr('string'),
//一对多关联,一的一方设置hasMay,多的一方设置belongsTo
comments: hasMany('comment'),
posts: hasMany('post')
});
post
// app/models/post.js
import Model from 'ember-data/model';
import attr from 'ember-data/attr';
import { belongsTo,hasMany } from 'ember-data/relationships';
export default Model.extend({
title: attr('string'),
publicDate: attr('date'),
content: attr('string'),
user: belongsTo('user'), //一对多关联,多的一方运用belongsTo
comments: hasMany('comment'),
tags: hasMany('tag')
});
comment
// app/models/comment.js
import Model from 'ember-data/model';
import attr from 'ember-data/attr';
import { belongsTo,hasMany } from 'ember-data/relationships';
export default Model.extend({
title: attr('string'),
publicDate: attr('date'),
content: attr('string'),
user: belongsTo('user'), //一对多关联,多的一方运用belongsTo
post: belongsTo('post')
});
tag
// app/models/tag.js
import Model from 'ember-data/model';
import attr from 'ember-data/attr';
import { belongsTo,hasMany } from 'ember-data/relationships';
export default Model.extend({
title: attr('string'),
posts: hasMany('post')
});
建立完模子以后,先从user最先,简朴做一个列表显现一切user,并在在列表页面能够新增、修正、删除user,完成最常见的CRUD操纵。在完成的过程当中插进去adapter和serializer的内容。
用户列表
用户列表页面也是很简朴的,就一个表格,个中引入了bootstrap款式。有关怎样引入请自身网上找答案吧。
列表模板
{{! app/templates/users/list.hbs 用户列表}}
<div class="row">
<div class="col-md-1 col-sx-11 col-md-offset-11 col-sx-offset-11">
{{#link-to 'users.new' class="btn btn-success"}}新增{{/link-to}}
</div>
</div>
<div class="row">
<table class="table table-striped table-hover">
<thead>
<tr>
<th>
用户名
</th>
<th>
华诞
</th>
<th>
地点
</th>
<th>
操纵
</th>
</tr>
</thead>
<tbody>
{{#each model as |user|}}
<tr>
<td>
{{user.name}}
</td>
<td>
{{user.birth}}
</td>
<td>
{{user.addr}}
</td>
<td>
{{#link-to 'users.edit' user.id}}修正{{/link-to}}
|
<a>删除</a>
</td>
</tr>
{{/each}}
</tbody>
</table>
</div>
列表路由设置
import Ember from 'ember';
export default Ember.Route.extend({
model() {
return this.store.findAll('user');
}
});
列表的路由也很简朴,直接猎取一切的user纪录,并返回到模板中,在模板中方便出每一个纪录。
待项目重启完成,直接预览http://localhost:4200/users/list,能够看到页面上什么也没有显现,翻开浏览器控制台能够看到以下毛病:
很显然我们的项目中确切没有供应要求http://localhost:4200/users
的后端效劳,而且项目也没有链接其他任何数据效劳(比方Firebase),那末怎样让Ember项目链接到我自身的数据库上呢?
在此,先引入数据效劳顺序,前面引见过,本例子运用Mongodb。效劳端顺序请看adapter-serializer-server,关于效劳端的内容我就部过量引见,你只须要晓得这个效劳顺序能够接收、返回的数据花样是jsonapi就好了。然后启动后端效劳顺序。
那末怎样让Ember项目链接到我的后端效劳呢??很简朴,只须要重写适配器的一个属性即可。下面运用Ember CLI称号建立一个适配器。
ember g adapter application
适配器建立终了以后,我们直接在适配器中接入自身的后端效劳。代码以下:
// app/adapters/application.js
import JSONAPIAdapter from 'ember-data/adapters/json-api';
export default JSONAPIAdapter.extend({
host: 'http://localhost:3000'
});
http://localhost:3000
是adapter-serializer-server启动后供应效劳的url。项目启动终了后能够看到浏览器控制台的毛病消逝了!而且在“NetWork”标签下能够看到有一个要求http://localhost:3000/users
点击这个要求,检察要求的“Response”能够看到返回的数据,比方下面的数据花样:
{
"links": {
"self": "http://localhost:3000/users"
},
"data": [
{
"id": "5753d7090280777c2381a0dd",
"type": "users",
"attributes": {
"name": "日期修正333",
"password": "11",
"addr": "地点地点地点地点",
"birth": "2016-06-04T00:00:00.000Z"
},
"links": {
"self": "http://127.0.0.1:3000/users/5753d7090280777c2381a0dd"
},
"relationships": {
"comments": {
"data": [],
"links": {
"self": "http://127.0.0.1:3000/users/5753d7090280777c2381a0dd/relationships/comments"
}
},
"posts": {
"data": [],
"links": {
"self": "http://127.0.0.1:3000/users/5753d7090280777c2381a0dd/relationships/posts"
}
}
}
},
{
"id": "5753d74a840db09d2352608a",
"type": "users",
"attributes": {
"name": "处理了跨域题目",
"password": "123132",
"addr": "范文芳啊的份水电费 测试服我飞"
},
"links": {
"self": "http://127.0.0.1:3000/users/5753d74a840db09d2352608a"
},
"relationships": {
"comments": {
"data": [],
"links": {
"self": "http://127.0.0.1:3000/users/5753d74a840db09d2352608a/relationships/comments"
}
},
"posts": {
"data": [],
"links": {
"self": "http://127.0.0.1:3000/users/5753d74a840db09d2352608a/relationships/posts"
}
}
}
},
{
"id": "57545597840db09d2352608b",
"type": "users",
"attributes": {
"name": "测试日期控件",
"password": "123123",
"addr": "适配器和序列化器示例"
},
"links": {
"self": "http://127.0.0.1:3000/users/57545597840db09d2352608b"
},
"relationships": {
"comments": {
"data": [],
"links": {
"self": "http://127.0.0.1:3000/users/57545597840db09d2352608b/relationships/comments"
}
},
"posts": {
"data": [],
"links": {
"self": "http://127.0.0.1:3000/users/57545597840db09d2352608b/relationships/posts"
}
}
}
}
]
}
由于我项目已有了3条数据了,所以跟你的能够有些许差别,然则数据的花样是一致的。这个数据的花样是遵照jsonapi范例的。
上述代码所演示的是自定义适配器最最经常运用的一个功用,假如你后端返回的数据是完整遵照jsonapi范例的险些不须要再做其他任何修正了。如许就已完成自定义适配器的工作了!然则既然在此特地引见适配器和序列化器固然不会只是引见这一个属性host
就完了,背面将陆陆续续引见其他的属性,以及怎样运用serializer。
继承完成user模块。
新增user
user模板
{{! app/templates/users/new.hbs 新增user}}
<form>
{{user-form model=model}}
<button type="submit" class="btn btn-success" {{action 'saveUser' model}}>保留</button>
</form>
user路由
直接在model
回调中返回一个空的实例对象。轻易保留。
// app/routes/users/new.js
import Ember from 'ember';
export default Ember.Route.extend({
model() {
return this.store.createRecord('user');
},
actions: {
saveUser(user) {
user.save().then(() => {
this.transitionTo('users.list');// 保留胜利转到列表页面
});
}
}
});
修正user
user模板
{{! app/templates/users/edit.hbs 修正user}}
<form>
{{user-form model=model}}
<button type="submit" class="btn btn-success" {{action 'updateUser' model}}>保留</button>
{{#link-to 'users.list' class="btn btn-default"}}作废{{/link-to}}
</form>
user路由
在修正的要领中先挪用findRecord
要领查询出被修正的数据,然后更新修正的属性,再挪用save
要领保留修正的内容。
// app/routes/users/edit.js
import Ember from 'ember';
export default Ember.Route.extend({
// 依据ID查询
model(params) {
return this.store.findRecord('user', params.user_id);
},
actions: {
updateUser(user) {
this.store.findRecord('user', user.get('id')).then((u) => {
u.set('name', user.get('name'));
u.set('addr', user.get('addr'));
u.set('birth', user.get('birth'));
u.set('addr', user.get('addr'));
u.save(); //保留修正的属性值
});
this.transitionTo('users.list'); //转到列表页面
}
}
});
由于新增、修正user模板都用到供一个表单,提取到一个组件中。
ember g component user-form
文件代码就不贴出来了,有须要请点击检察github代码。然后在组件类中初始化了一个日期控件bootstrap-datepicker,插件直接在app/index.html
中引入了,下面是组件类代码:
// app/components/user-form.js
import Ember from 'ember';
export default Ember.Component.extend({
didInsertElement() {
this._super(...arguments); //记得挪用父类的组织要领
//初始化日期控件
Ember.$(".datepicker").datepicker({format:'yyyy-mm-dd', autoclose: true});
}
});
user列表、新增user、修正user界面结果以下截图:
到此完成了相似运用Firebase的数据存储功用,能够准确保留数据到自身的数据库中。能够一定的是数据已准确保留到我的MongoDB中,我就不再截图了!对象的CRUD功用已完成,后续我就不再引见post
、comment
、tag
的CRUD了,后续偏重引见适配器、序列化器的其他属性以及模子之间的关联关联(比方一对多、多对多)。
假如你仔细看前面的第一个截图你会发明列表上显现的时刻花样不友好,不是我们所习气看的时刻花样,那末怎样处置惩罚呢?花样化时刻的体式格局有许多,能够自定义Ember helper花样化时刻,也能够定义模子user
的属性birth
为date
范例,在此我特地定义为了string
是为了演示serializer的运用。我们能够在自定义的serializer中花样化返回的数据。下面起首建立serializer。
ember g serializer application
在序列化器中挪用相应要求的要领normalizeResponse
花样化返回的数据。代码以下:
// app/serializers/application.js
import JSONAPISerializer from 'ember-data/serializers/json-api';
export default JSONAPISerializer.extend({
// 此要领相应要求的时刻实行
normalizeResponse(store, primaryModelClass, payload, id, requestType) {
// 花样化birth的时刻花样
//默许显现的时刻花样为 2016-06-09T00:00:00.000Z ,简朴处置惩罚直接截取前面的10位
// 只是为了演示要领normalizeResponse的运用,现实项目中不引荐如许的用法,由于须要遍历每一个数据,效力不好
payload.data.forEach(function(item, index) {
var oldDate = item.attributes.birth;
if (oldDate) {
oldDate = oldDate.substring(0, 10);
}
item.attributes.birth = oldDate;
oldDate = null;
});
return this._super(...arguments);
}
// 此要领发送要求的时刻回实行
// serialize(snapshot, options) {
//
// }
});
然则现实运用过程当中不引荐运用这类体式格局花样化数据,除非是不得已,由于须要遍历每一个纪录去修正属性的值,假如数据量大影响效力,最好的体式格局是自定义helper
在模板上花样化。把花样化的操纵放到显现数据的时刻。
上述就是serializer的一个简朴有用示例。
adapter和serializer内容比较多,分为2篇引见,下一篇我回在本篇的基础上逐一引见adapter和serializer的经常运用属性、要领的运用。
adapter与serializer运用下篇
项目源码:https://github.com/ubuntuvim/ember-adapter-serializer
背景源码:https://github.com/ubuntuvim/adapter-serializer-server
有疑问迎接在下方批评区给我留言,我会尽快为你解答,假如你以为本文能给你协助,或许以为博主写作辛劳也迎接点击右上角“为博主充电”给我打赏,你的一定对我来说是最大的动力。O(∩_∩)O哈哈~