Emberjs 默認使用 JSONAPISerializer ,在咱們的項目中也是使用JSONAPISerializer.因此只是涉及關於 JSONAPISerializer 的相關內容。
@[TOC]javascript
在目前的版本中,後端咱們使用 大駝峯法命名,可是前端基本使用都是 駝峯法,致使有所差別,在數據獲取展現過程當中,須要統一 key 的名稱。這時就可使用 keyForAttribute
這個方法來實現咱們的需求,好比:前端
// 後端數據 { 'data': [{ 'type': 'people', 'id': '123', 'attributes': { 'FirstName': 'Jeff', 'LastName': 'Atwood', 'Birthday': new Date().getTime() } }, { 'type': 'people', 'id': '124', 'attributes': { 'FirstName': 'Yehuda', 'LastName': 'Katz', 'Birthday': new Date('2011-11-11 11:11:11').getTime() } }] };
而在前端 咱們定義的屬性名爲:java
// person/model.js import DS from 'ember-data'; export default DS.Model.extend({ firstName: DS.attr('string'), lastName: DS.attr('string'), birthday: DS.attr('date') });
前端使用的是 經常使用的駝峯命名法,在這樣的情形下(先後端屬性名字不一致),咱們就須要修改向後端申請的屬性名稱來將後端數據合理的傳遞到咱們前端定義的屬性名上來:git
// person/serializer.js import DS from 'ember-data'; import { camelize, capitalize } from '@ember/string'; export default DS.JSONAPISerializer.extend({ keyForAttribute(key) { let newKey = camelize(key); return capitalize(newKey); } });
keyForAttribute
這個方法接受 前端 定義的屬性名稱爲參數,如當下的firstName
等,通過轉換爲後端相同的屬性名,如FirstName
。這樣來達到先後端通訊的要求。github
在上面咱們能夠看到,後端返回數據中的 type
爲people
,可是前端尋找的type
卻爲person
,這是由於 Ember Data 中的約定的關係,可是若是咱們就想讓它尋找的type
爲 people
呢?那咱們就須要用到 modelNameFromPayloadKey
這個方法:後端
// people/serilizer.js import DS from 'ember-data'; import { camelize, capitalize } from '@ember/string'; export default DS.JSONAPISerializer.extend({ modelNameFromPayloadKey(key) { return key; }, keyForAttribute(key) { let newKey = camelize(key); return capitalize(newKey); } });
經過複寫這個方法就能夠禁止 modelName
的單複數轉換了。
目前咱們是在單獨的 model 下執行的這個 serializer
的幾個方法,若是須要在全局則須要將 serializer.js
文件寫在 application
下1。
相應的,還會有payloadKeyFromModelName
api
## IDs
在 JSONAPI 中 每一個條目都應該使用 id 中的值來做爲爲一標識,先後端都應如此,若是後端沒有將 id 做爲惟一標識,那麼就可使用 primaryKey
這個屬性來定義一個惟一標識:
這是前端定義的:瀏覽器
// people/serilizer.js import DS from 'ember-data'; import { camelize, capitalize } from '@ember/string'; export default DS.JSONAPISerializer.extend({ primaryKey: 'pKey', modelNameFromPayloadKey(key) { return key; }, keyForAttribute(key) { let newKey = camelize(key); return capitalize(newKey); } });
然後端傳來的數據便可變動爲:app
// 後端數據 { 'data': [{ 'type': 'people', 'pKey': '123', 'attributes': { 'FirstName': 'Jeff', 'LastName': 'Atwood', 'Birthday': new Date().getTime() } }, { 'type': 'people', 'pKey': '124', 'attributes': { 'FirstName': 'Yehuda', 'LastName': 'Katz', 'Birthday': new Date('2011-11-11 11:11:11').getTime() } }] };
在平常工做中的難題之一就是命名,而每每後端的命名和前端的不太一致,若是咱們作了大量的展現工做,再更換名稱那就有點比較麻煩,這時候咱們可使用 attrs
屬性來達到咱們的目的:
後端傳輸的數據中有一:this
// ... ThePersonSelfHeight:176 // ...
前端認爲這個名字過於複雜因此想alias:
// people/serilizer.js import DS from 'ember-data'; export default DS.JSONAPISerializer.extend({ primaryKey: 'pKey', attrs: { height: 'ThePersonSelfHeight' }, // ... });
同時也須要在model.js
文件進行相應的修改:
// people/model.js // ... height: DS.attr('number') // ...
便可在頁面中使用.height
展現ThePersonSelfHeight
屬性的值。
在工做中,後端傳回來的數據每每會有些許嵌套或者是後端人員有本身的思考方式致使數據的結構和咱們設想的有些許不一樣。這個時候咱們能夠經過 serialize()
以及 normalizeResponse()
這兩個方法來實現咱們的需求。
好比後端傳給咱們的數據有:
data: { type: 'phone', id: 1, attributes: { brand: 'Nokia', capacity: 64, size: { width: 70.9, height: 143.6, depth: 7.7, weight: 177 }, display: 5.8 } }
而咱們在數據顯示中但願能直接展現的depth
,而不想從size
中取:
// phone/model.js import DS from 'ember-data'; export default DS.Model.extend({ brand: DS.attr('string'), capacity: DS.attr('number'), depth: DS.attr('number'), display: DS.attr('number') });
咱們能夠經過 serializer.js
中的 normalizeResponse()
方法來實現咱們的需求:
// phone/serializer.js // ... normalizeResponse(store, primaryModelClass, payload, id, requestType) { payload.data.attributes.depth = payload.data.attributes.size.depth; delete payload.data.attributes.size; return this._super(...arguments); }
以後在 route.js
中咱們請求數據:
// route.js // ... model() { return this.get('store').queryRecord('phone',{}) }
這樣頁面中咱們就能夠直接獲取 depth
的值了:
<tr> <td>{{model.brand}}</td> <td>{{model.capacity}}</td> <td>{{model.depth}}</td> <td>{{model.display}}</td> </tr>
除了 normalizeResponse()
方法,還有其餘的幾個方法,如:
// phone/serializer.js // ... normalize(typeClass, hash) { hash.attributes.depth = hash.attributes.size.depth; delete hash.attributes.size; return this._super.apply(this, arguments); }
也能夠起到相同的做用。這個方法能夠在application
中定義特定的 typeClass
來針對調用。
在本文中咱們獲取數據使用了 queryRecord()
,因此咱們還可使用:
// phone/serializer.js // ... normalizeQueryRecordResponse(store, primaryModelClass, payload, id, requestType) { payload.data.attributes.depth = payload.data.attributes.size.depth; delete payload.data.attributes.size; return this._super(...arguments); },
相同的也能夠聯想,當咱們獲取數據爲:
// route.js mode() { return this.get('store').findAll('phone'); }
這種狀況的時候,可使用:
// phone/serializer.js normalizeFindAllResponse(store, primaryModelClass, payload) { let data = payload.data.attributes; payload.data.attributes.depth = data.size ? data.size.depth : data.depth; delete payload.data.attributes.size; return this._super(...arguments); }
依然能夠達到咱們的目的。Emberjs 還提供其餘的 normalize hook:
normalizeFindBelongsToResponse()
normalizeFindHasManyResponse()
normalizeFindManyResponse()
normalizeFindRecordResponse()
normalizeQueryResponse()
等其餘修改建立的請求。
這個 hook 的使用須要從 建立一個 record 提及:
// arcicle/route.js or controller.js let articles = this.get('store').createRecord('article', { id: new Date().getTime(), title: 'how to use serialize', body: 'let try' });
在建立了 record 以後,能夠在 EmberInspector 中的 Data
中查看到相應的 data。同時在 serializer.js
中添加 normalizeCreateRecordResponse()
:
// article/serializer.js import DS from 'ember-data'; export default DS.JSONAPISerializer.extend({ normalizeCreateRecordResponse(store, primaryModelClass, payload, id, requestType) { console.log(payload); return this._super(...arguments); } });
這時在瀏覽器看到這個 hook 並無執行。這個hook 執行的時機時在 保存 record 的時候:
// article/route.js or controller.js // ... articles.save()
刷新後便可看到 normalizeCreateRecordResponse()
此鉤子已經被執行。
同理,其餘的更新/刪除類似:
至此 DS.JSONAPISerialize 的相關屬性與method 已解釋完成。
Written By FrankWang.
serializer.js
文件除了最頂層的是在 application
文件夾下,其他是跟 model
名稱走的,不是跟路由名稱。 ↩