Define custom root json node on ember serializer - javascript

I'm trying to get brands items from my REST API with ember; but my API response does not match with ember-data expected. for example:
My model:
import DS from 'ember-data';
export default DS.Model.extend({
name: DS.attr('string'),
isActive: DS.attr('boolean')
});
My API url: http://localhost:3000/api/brands
its response with:
{"success":true,
"data":[
{"id":1,"name":"Mine","isActive":true,"createdAt":"2017-04-23T20:36:49.000Z","updatedAt":"2017-04-23T20:44:32.000Z"},
{"id":2,"name":"forever","isActive":true,"createdAt":"2017-04-23T20:41:14.000Z","updatedAt":"2017-04-23T20:43:57.000Z"}
]
}
but, Ember is expecting some like this:
"brands": [{
"id": 1,
"name": "foo",
"isActive": "foo"
}]
I'm trying to change the root json node in serializer called brand.js, but I can not make it work. :(
here my serializer/brand.js
import DS from 'ember-data';
export default DS.RESTSerializer.extend({
});
and my adapters/application.js
import DS from 'ember-data';
import DataAdapterMixin from 'ember-simple-auth/mixins/data-adapter-mixin';
import config from '../config/environment';
export default DS.RESTAdapter.extend(DataAdapterMixin, {
host: `${config.host}`,
namespace: `${config.namespace}`,
authorizer: 'authorizer:custom'
});
on browser console this message appears:
WARNING: Encountered "success" in payload, but no model was found for model name "success" (resolved model name using vanely-web#serializer:brand:.modelNameFromPayloadKey("success"))
WARNING: Encountered "data" in payload, but no model was found for model name "datum" (resolved model name using vanely-web#serializer:brand:.modelNameFromPayloadKey("data"))
How can I say to ember where the correct data is?.Some help is appreciated.
Sorry if my English is not well.

As you already did, you can override the RESTSerializer for every model.
What you want to achieve is response normalization. You can normalize your response by overriding normalizeResponse in your serializer (see the docs):
import Ember from 'ember';
import DS from 'ember-data';
const {
RESTSerializer
} = DS;
const {
get
} = Ember;
export default RESTSerializer.extend({
normalizeResponse(store, primaryModelClass, payload, id, requestType) {
// Only do normalization for reading:
if(requestType !== 'createRecord' && requestType !== 'updateRecord' && requestType !== 'deleteRecord') {
// Do your normalization here. For example (not tested):
payload = {
brands: get(payload, 'data')
};
}
return this._super(store, primaryModelClass, payload, id, requestType);
}
});
Instead of overriding normalizeResponse, you could also override the other normalization methods.

Related

Ember js service and filterBy

i have a service to manage all the errors and alerts in my app. and the code looks like this
Service
import Ember from 'ember';
export default Ember.Service.extend({
messages: null,
init() {
this._super(...arguments);
this.set('messages', []);
},
add: function (severity, msg, messageType) {
if (severity === 'error') {severity = 'danger';}
var msgObject ={
severity: severity,
messageType: messageType,
msg: msg,
msgId: new Date()
};
this.get('messages').pushObject(msgObject);
},
remove(msgId) {
this.get('messages').removeObject(msgId);
},
empty() {
this.get('messages').clear();
}
});
Component
import Ember from 'ember';
export default Ember.Component.extend({
messageType:'global',
messageHandler: Ember.inject.service(),
messages: function(){
return this.get('messageHandler.messages').filterBy('messageType',this.get('messageType'));
}.property('messageHandler.messages'),
actions : {
dismissAllAlerts: function(){
this.get('messageHandler').empty();
},
dismissAlert: function(msgId){
this.get('messageHandler').remove(msgId);
}
}
});
Initializer
export function initialize(container, application) {
application.inject('component', 'messageHandler', 'service:message-handler');
}
export default {
name: 'message-handler',
initialize : initialize
};
Template
import Ember from 'ember';
export default Ember.Component.extend({
messageType:'global',
messageHandler: Ember.inject.service(),
messages: function(){
return this.get('messageHandler.messages');
}.property('messageHandler.messages'),
actions : {
dismissAllAlerts: function(){
this.get('messageHandler').empty();
},
dismissAlert: function(msgId){
this.get('messageHandler').remove(msgId);
}
}
});
and whenever there is an error i will add it like this
this.get('messageHandler').add('error',"Unable to get ossoi details","global");
my problem is the filterBy in the component is not working. if i remove the filterBy() it works and i can see the error in the template. am kinda new to ember so if anyone can help me figure out what am missing here or if there is a better way of doing this please let me know
filterBy usage is good and it should be working well. but messages computed property will not be recomputed whenever you add/remove item from messageHandler.messages.
messages: Ember.computed('messageHandler.messages.[]', function() {
return this.get('messageHandler.messages').filterBy('messageType', this.get('messageType'));
}),
In the above code I used messageHandler.messages.[] as dependant key for the messages computed property so that it will be called for add/remove items.
Refer:https://guides.emberjs.com/v2.13.0/object-model/computed-properties-and-aggregate-data/
Computed properties dependent on an array using the [] key will only
update if items are added to or removed from the array, or if the
array property is set to a different array.

Ember model finding records

I'm having trouble getting Ember's queryRecord to work properly. I'm trying to grab a site config from the server.
//app/routes/application.js
model: function(){
return this.get('store').queryRecord('config',{}).then(function(config) {
console.log(config.get('appname'));
});
}
//app/adapters/config.js
import DS from "ember-data";
import ENV from './../config/environment';
export default DS.Adapter.extend({
queryRecord(modelName, query) {
return Ember.$.getJSON( ENV.APP.apiFull + 'config' );
}
});
//app/serializers/applications.js
import DS from 'ember-data';
export default DS.RESTSerializer.extend({
keyForAttribute: function(attr, method) {
return Ember.String.underscore(attr).toUpperCase();
}
});
//JSON returning from server AJAX call
{"config":{"id":1,"environment": "development", "appname":"Sample App Name"}}
The console.log statement in //app/routes/application is returning undefined. This all seems to match up with the Ember documentation for version 2.9. What am I doing incorrectly?
#Lux, thanks for pointing me towards the serializer. That led to me looking at the model member names and I found that I had underscored them in the model, but not in the JSON coming from the server.

Save associated record in Ember

I am a beginner in Ember and trying to implement a simple post and comment app.
I have a rails background and hence i'm using Rails API for this.
I have followed a tutorial and i'm able to save a post, fetch all its comments and delete the post. However i'm having issues in saving comment related to the post.
Following is the code for models
post.js
import DS from 'ember-data';
export default DS.Model.extend({
title: DS.attr('string'),
body: DS.attr('string'),
comments: DS.hasMany('comment')
});
comment.js
import DS from 'ember-data';
export default DS.Model.extend({
author: DS.attr('string'),
body: DS.attr('string'),
post: DS.belongsTo('post')
});
routes/post/comment/new.js
import Ember from 'ember';
export default Ember.Route.extend({
model() {
return {};
},
renderTemplate() {
this.render('post.comment.new', { into: 'application' });
},
actions: {
save() {
const post = this.modelFor('post');
const newComment = this.get('store').createRecord('comment', this.currentModel);
newComment.set('post', post);
newComment.save().then(() => {
this.transitionTo('post', post);
});
},
cancel() {
this.transitionTo('post', this.modelFor('post'));
}
}
});
router.js
import Ember from 'ember';
import config from './config/environment';
const Router = Ember.Router.extend({
location: config.locationType,
rootURL: config.rootURL
});
Router.map(function() {
this.route('posts');
this.route('post.new', { path: 'posts/new' });
this.resource('post', { path: 'posts/:post_id' }, function() {
this.route('comment.new', { path: 'comments/new' });
});
});
export default Router;
Saving the comment is where i'm facing an issue. This is really strange but while saving the comment, the params passed to the server looks like
Parameters: {"comment"=>{"author"=>"dsa", "body"=>"asd", "post"=>"9"}}
Unpermitted parameter: post
From what i understand, the parameter should be post_id and not post. If post is being passed, then it should be object. I may be wrong of course because i don't have a clear understanding in Ember yet.
On randomly fiddling with the code, i found that if i replace the relationship in comments model from
post: DS.belongsTo('post')
to
post_id: DS.belongsTo('post')
the params passed to server are
Parameters: {"comment"=>{"author"=>"fg", "body"=>"dfs", "post_id"=>nil}}
This however doesn't actually pass the post_id as its nil.
This might be absolutely wrong and not how its supposed to work but i'm clueless.
Thanks for any help.
Create comment serializer and override keyForRelationship method like below :
keyForRelationship(key/*, relationship, method*/) {
if(key === 'post') return 'post_id';
return this._super(...arguments);
}
and the post relation should be :
post: DS.belongsTo('post')

Error while trying to load ember data model from REST API

Version: Ember 2.11
I am trying to use Ember data model to load the data from REST API but it is failing with error message as
"ember.debug.js:17634 TypeError: Cannot read property 'type' of undefined
at Class._pushInternalModel (store.js:2005)
Here is more details:
1. REST API response is:
{
"sfresults":[
{
"url":"https://google.com/1",
"title":"Titl1",
"description":"Description1",
"type":"KB",
"lastModifiedDate":"12/23/16",
"viewScore":"86.12006476690622",
"caseNumber":"case1",
"id":"cd4ac3e8-c3ac-4be5-ad11-c62a85ddf289"
},
{
"url":"https://google.com/2",
"title":"Titl2",
"description":"Description2",
"type":"KB",
"lastModifiedDate":"12/23/16",
"viewScore":"86.12006476690622",
"caseNumber":"case2",
"id":"cd4ac3e8-c3ac-4be5-ad11-c62a85ddf289"
},
],
"message":"SUCCESS",
"id":"3bd116c7-db63-4277-8ace-a7ea846a04ee"
}
Controller code:
let sfdata = this.store.query('sfresult',{ 'searchText': inputSearchText, 'searchType' : 'SF' } );
this.set('sfresult', sfdata);
My Models
sfresult.js
import DS from 'ember-data';
export default DS.Model.extend({
sfresults: DS.hasMany('sfresults'),
message: DS.attr('string')
});
sfresults.js
import DS from 'ember-data';
export default DS.Model.extend({
title: DS.attr('string'),
description: DS.attr('string'),
caseNumber: DS.attr('string'),
lastModifiedDate: DS.attr('string'),
type: DS.attr('string'),
url: DS.attr('string'),
searchText: DS.attr('string'),
messageId: DS.attr('string')
});
export default DS.RESTAdapter.extend({
host: 'http://localhost:8080',
namespace: 'server'
});
Then i wanted to iterate sfresult and show it in the UI. but here as soon as API call response comes back it is unable to load into ember data models. fails with above error.
Note: if i try without hasMany model it works fine - meaning json response having array of elements and using only sfresults model without sfresult, but wanted to get the message in the JSON response to act accordingly - please ignore this statement if it is confusing a bit.
Any help would be greatly appreciated.
You'll need to make sure you are using the RESTSerializer. By default the serializer in a new app is JSONAPISerializer, which throws the error that you are seeing.

Ember.js length of array of related objects

Im using Ember Data and Ember CLI. I have a simple one-to-many relationship between two models. I'm trying to create a computed property that returns the number of items that are attached to the current model.
models/account.js
// Account model
import DS from 'ember-data';
export default DS.Model.extend({
name: DS.attr('string'),
notes: DS.hasMany('note', { async: true })
});
models/note.js
// Note model
import DS from 'ember-data';
export default DS.Model.extend({
body: DS.attr('string'),
date: DS.attr('number'), // unix timestamp
account: DS.belongsTo('account', { async: true })
});
controllers/account/index.js
// account/index controller
import Ember from 'ember';
export default Ember.ObjectController.extend({
oldNotesCount: function() {
var notes = this.get('notes');
console.log('=-=', notes.length); // undefined *****
return notes.length;
}.property('notes.#each')
});
How come notes.length is undefined?
I've simplified this example... I can't use {{notes.length}} in my situation as there will be more calculations going on—this is just the first step.
You marked notes association as async so this.get('notes') returns a promise. Promises do not have length property hence getting undefined.
To get data in an async association call then on returned promise with a function as argument. Association data will be passed to that function as first argument.
export default Ember.ObjectController.extend({
oldNotesCount: function() {
var _this = this;
this.get('notes').then(function(notes){
_this.set('oldNotesCount', notes.get('length');
});
return null;
}.property('notes.#each')
});

Categories