Ember Serializer

Emberjs uses JSONAPISerializer by default, and we used JSONAPISerializer in our project. So it’s just about JSONAPISerializer. @[TOC]

Front-end and back-end communication protocols

In the current version, we use the big hump method to name the back end, but the front end basically uses the hump method, resulting in some differences. In the process of data acquisition and display, we need to unify the name of the key. We can then use the keyForAttribute method to implement our requirements, such as:

// Back-end data
{
	'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('the 2011-11-11 11:11:11').getTime()
		}
	}]
};
Copy the code

On the front end we define a property called:

//	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')});Copy the code

The front-end uses the common hump nomenclature. In this case, we need to modify the attribute name applied by the back-end to properly transfer the back-end data to the attribute name defined by the front-end:

//	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);
		returncapitalize(newKey); }});Copy the code

KeyForAttribute The keyForAttribute method takes an attribute name defined on the front end as a parameter, such as the current firstName, and converts it to the same attribute name on the back end, such as firstName. In this way, the communication between the front and back ends can be achieved.

Front-end modelName changes

As you can see above, the back end returns Data with a type of people, but the front end looks for a type of Person because of the convention in Ember Data, but what if we just want it to look for a type of people? We need to use the modelNameFromPayloadKey method:

//	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);
		returncapitalize(newKey); }});Copy the code

Overwrite this method to disallow the singular and plural conversions of ModelNames. Currently, we execute the serializer methods under a separate model. If we need to use the serializer globally, we need to write the serializer. Js file under application [1]. And then there’s payloadKeyFromModelName

IDs

Each entry in the JSONAPI should use the value of the id as an id, both on the front and back ends. If the back end does not use the id as a unique id, a primaryKey property can be used to define a unique id: this is what the front end defines:

//	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);
		returncapitalize(newKey); }});Copy the code

The data from the backend can be changed to:

// Back-end data
{
	'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('the 2011-11-11 11:11:11').getTime()
		}
	}]
};
Copy the code

Shortened attribute name

One of the challenges in daily work is naming, and often the backend name and the front-end name do not match. If we do a lot of presentation work, it is a bit troublesome to change the name. In this case, we can use the attrs attribute to achieve our purpose:

	//	...
	ThePersonSelfHeight:176
	// ...
Copy the code

The front-end thinks the name is too complex and thinks alias:

//	people/serilizer.js
import DS from  'ember-data';
 
export  default  DS.JSONAPISerializer.extend({
	primaryKey: 'pKey'.attrs: {
		height: 'ThePersonSelfHeight'
	},
	// ...
});
Copy the code

You also need to modify the model.js file accordingly:

//	people/model.js
// ...
	height:  DS.attr('number')
// ...
Copy the code

Height Displays the value of the ThePersonSelfHeight property.

Format Response

At work, the data that comes back from the back end tends to be a little bit nested or the backend people have their own way of thinking and the structure of the data is a little bit different from what we expect. At this point we can implement our requirements through serialize() and normalizeResponse(). For example, the data sent to us by the back end is as follows:

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}}Copy the code

We want to show depth directly in the data display, instead of taking it from 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')});Copy the code

normalizeResponse()

We can do this with the normalizeResponse() method in serializer.js:

// 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); }Copy the code

Then in route.js we request data:

//	route.js
// ...
model() {
	return this.get('store').queryRecord('phone'}, {})Copy the code

So we can get depth directly from the page:

<tr>
	<td>{{model.brand}}</td>
	<td>{{model.capacity}}</td>
	<td>{{model.depth}}</td>
	<td>{{model.display}}</td>
</tr>
Copy the code

In addition to the normalizeResponse() method, there are several other methods, such as:

normalize()

//	phone/serializer.js
// ...
normalize(typeClass, hash) {
	hash.attributes.depth = hash.attributes.size.depth;
	delete hash.attributes.size;
	return  this._super.apply(this.arguments);
}
Copy the code

Can do the same thing. This method can define specific typeClass in the application for the call.

normalizeQueryRecordResponse()

In this article we get the data using queryRecord(), so we can also use:

//	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); },Copy the code

normalizeFindAllResponse()

The same can also be associated, when we obtain the data is:

// route.js
	mode() {
		return this.get('store').findAll('phone');
	}
Copy the code

In this case, you can use:

//	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); }Copy the code

We can still get what we want. Emberjs also provides other Normalize hooks:

  • normalizeFindBelongsToResponse()
  • normalizeFindHasManyResponse()
  • normalizeFindManyResponse()
  • normalizeFindRecordResponse()
  • normalizeQueryResponse()

Other requests to modify the creation.

normalizeCreateRecordResponse()

To use this hook, we need to start by creating a 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'
});

Copy the code

After the Record is created, the corresponding Data can be viewed in the Data in the EmberInspector. At the same time in the serializer. Add normalizeCreateRecordResponse js () :

//	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);
	}
});
Copy the code

The browser sees that the hook is not executed. This hook is executed when the record is saved:

//	article/route.js or controller.js
// ...
articles.save()
Copy the code

After the refresh can see normalizeCreateRecordResponse () have been executed this hook. Similarly, other updates/deletions are similar:

  • normalizeDeleteRecordResponse
  • normalizeSaveResponse
  • normalizeUpdateRecordResponse

The related properties and method of ds.jsonapiserialize have now been explained.

Written By FrankWang.


  1. The serializer. Js file is stored in the application folder at the top level and follows the model name, not the route name. ↩ ︎