Ember Data Polymorphic Relationship: Not Using Correct Model - javascript

Using an older version of ember(1.7.1) and ember-data(1.0.0 beta 12) as trying to upgrade to 2.0. When loading my application I get the following warning:
WARNING: The payload for 'App.QPAC' contains these unknown keys: [abs_parent_gbid,author,comments,course,follows,has_more_comments,is_announcement,more_comments_count,resource_uri,title]. Make sure they've been defined in your model.
Here is my model code (There are other models than post but they aren't being loaded in this instance).
App.Feedstory = DS.Model.extend({
global_id: DS.attr('string'),
story_type: DS.attr('string'),
story: DS.belongsTo('qPAC', {polymorphic: true}),
});
App.QPAC = DS.Model.extend({
global_id: DS.attr('string'),
global_code: DS.attr('string'),
body: DS.attr('string'),
});
App.Post = App.QPAC.extend({
title: DS.attr('string'),
is_announcement: DS.attr('boolean'),
author: DS.belongsTo('user'),
comments: DS.hasMany('comment'),
});
Ember inspector is showing me that the all the feedstory objects of type Post are being found and it shows in the Post attributes that the correct IDs are being loaded but not the other attributes.
The warning says it's looking for the post attributes in the App.QPAC model and not App.Post. Any ideas?
Edit: Added serializers and adapters
App.ApplicationAdapter = DS.RESTAdapter.extend({
namespace: 'api/v2'
});
App.FeedstorySerializer = DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, {
primaryKey: 'global_id',
attrs: {
pin: {embedded: 'always' },
story: {embedded: 'always'},
},
});
App.PostSerializer = DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, {
primaryKey: 'global_id',
attrs: {
author: {embedded: 'always' },
course: {embedded: 'always' },
pin: {embedded: 'always' },
comments: {embedded: 'always'},
follows: {embedded: 'always'},
},
normalize: function(type, hash, prop) {
if (Object.keys(hash.comments).length === 0) {
hash.comments = null;
}
if (Object.keys(hash.follows).length === 0) {
hash.follows = null;
}
return this._super(type, hash, prop);
},
});

Related

emberJS does not display model data

I am using emberJS to display data obtained from REST API. My ember app connects to REST server and server returns the JSON data, but when I try to display id of my restaurant in the template I get this output:
Restaurant id is:
Here are my models:
import DS from 'ember-data';
//restaurant.js model
export default DS.Model.extend({
restaurantId: DS.attr('int'),
name: DS.attr('string'),
rating: DS.attr('double'),
phone: DS.attr('double'),
reservationPrice: DS.attr('double'),
workingHours: DS.attr('string'),
deals: DS.attr('string'),
image: DS.attr('string'),
//Relations
coordinates: DS.belongsTo('coordinates'),
address: DS.belongsTo('address')
});
//coordinates.js model
import DS from 'ember-data';
export default DS.Model.extend({
latitude: DS.attr("double"),
longitude: DS.attr("double"),
//Relations
restaurant: DS.belongsTo('restaurant')
});
//address.js model
import DS from 'ember-data';
export default DS.Model.extend({
streetName: DS.attr("string"),
city: DS.attr("string"),
country: DS.attr("string"),
//Relations
restaurant: DS.belongsTo('restaurant')
});
my template:
Restaurant id is: <br>
{{restaurant.restaurantId}}
<br>
{{model.restaurantId}}
{{#each model as |restaurant|}}
<h2>{{restaurant.image}}</h2>
{{/each}}
and my route:
//restaurant.js route
import Ember from 'ember';
export default Ember.Route.extend({
model() {
return this.store.findAll('restaurant');
}
});
and of course, my serializer:
import DS from 'ember-data';
export default DS.RESTSerializer.extend({
normalizeFindAllResponse(store, type, payload){
return {
id: "restaurantId",
data: {
type: type.modelName,
id: "restaurantId",
attributes: {
id: "restaurantId",
restaurantId: payload.restaurantId,
name: payload.name,
address: payload.address,
phone: payload.phone,
workingHours: payload.workingHours,
rating: payload.rating,
image: payload.image
}
}
};
}
});
Here is the JSON I get from server:
[ {
"restaurantId" : 1,
"name" : "Some name",
"address" : {
"streetName" : "some street",
"city" : "some town",
"country" : "some country"
},
"phone" : 984894,
"workingHours" : "08:00 - 23:00",
"rating" : 3.0,
"image" : "www.somelink.com"
},
...
]
I can see in Chrome inspector that my ember App makes a request to server and server responds with JSON. And there are no errors nor warnings, but my model data just does not get displayed. Any help is appreciated.
edit:
I wrote this normalizeFindRecord in my serializer, and now it looks like this:
normalizeFindRecordResponse(store, type, payload){
return {
data: {
type: type.modelName,
id: "restaurantId",
address: DS.belongsTo('restaurant', {embedded: true} ),
attributes: {
restaurantId: payload.restaurantId,
name: payload.name,
address: payload.address,
phone: payload.phone,
workingHours: payload.workingHours,
rating: payload.rating,
image: payload.image,
coordinates: payload.coordinates
}
}
};
}
and now when I try route this.store.findRecord('restaurant', 1); I get
Restaurant id is:
1
but the findAllRoute does still not work.

codeschool emberjs 7.4 rating a product not working

I have been battling the level 7.4 review question with no luck:
Rating isn’t a object like Review was, so our createRating function will be a little different. We can addObject the currently selected rating to the array of ratings on our product. You’ll need to save the product to update it in the store.
I can not seem to get the value from the select list. Can anyone point me in the right direction or collaborate on this?
My handlebars code:
<script type='text/x-handlebars' data-template-name='product'>
<div class='row'>
<div class='col-sm-7'>
<h2>{{title}}</h2>
<h3 class='text-success'>${{price}}</h3>
<p class='text-muted'>{{description}}</p>
<p class='text-muted'>This Product has a {{rating}} star rating!</p>
<p>Finely crafted by {{#link-to 'contact' crafter}}{{crafter.name}}{{/link-to}}.</p>
{{render 'reviews' reviews}}
<div class='new-rating'>
<h3>Rate {{title}}</h3>
</div>
<div class='new-review'>
<h3>Review {{title}}</h3>
{{#if text}}
<p class='text-muted'>{{text}}</p>
{{/if}}
{{textarea valueBinding='text'}}
<button {{action 'createReview'}} class='btn-primary'>Review</button>
</div>
</div>
<div class='col-sm-5'>
<img {{bind-attr src='image'}} class='img-thumbnail img-rounded'/>
</div>
</div>
{{contact-details contact=crafter className='row'}}
{{view Ember.Select content=ratings value=selectedRating}}
<button {{action 'createRating'}} class='btn-primary'>Rating</button>
</script>
My js code:
var App = Ember.Application.create({
LOG_TRANSITIONS: true
});
App.Router.map(function() {
this.route('credits', { path: '/thanks' });
this.resource('products', function() {
this.resource('product', { path: '/:product_id' });
this.route('onsale');
this.route('deals');
});
this.resource('contacts', function() {
this.resource('contact', { path: '/:contact_id' });
});
});
App.IndexController = Ember.ArrayController.extend({
productsCount: Ember.computed.alias('length'),
logo: 'images/logo-small.png',
time: function() {
return (new Date()).toDateString();
}.property(),
onSale: function() {
return this.filterBy('isOnSale').slice(0,3);
}.property('#each.isOnSale')
});
App.ContactsIndexController = Ember.Controller.extend({
contactName: 'Anostagia',
avatar: 'images/avatar.png',
open: function() {
return ((new Date()).getDay() === 0) ? "Closed" : "Open";
}.property()
});
App.ProductsController = Ember.ArrayController.extend({
sortProperties: ['title']
});
App.ContactsController = Ember.ArrayController.extend({
sortProperties: ['name'],
contactsCount: Ember.computed.alias('length')
});
App.ReviewsController = Ember.ArrayController.extend({
sortProperties: ['reviewedAt'],
sortAscending: false
});
App.ContactProductsController = Ember.ArrayController.extend({
sortProperties: ['title']
});
App.ProductController = Ember.ObjectController.extend({
text: '',
ratings: [1,2,3,4,5],
selectedRating: 5,
actions: {
createReview: function(){
var review = this.store.createRecord('review', {
text: this.get('text'),
product: this.get('model'),
reviewedAt: new Date()
});
var controller = this;
review.save().then(function() {
controller.set('text', '');
controller.get('model.reviews').addObject(review);
});
},
createRating: function(){
var rating = this.store.createRecord('rating', {
rating: this.get('selectedRating.value'),
product: this.get('model'),
reviewedAt: new Date()
});
var controller = this;
rating.save().then(function() {
controller.get('model.rating').addObject(rating);
});
}
}
});
App.ProductsRoute = Ember.Route.extend({
model: function() {
return this.store.findAll('product');
}
});
App.ContactsRoute = Ember.Route.extend({
model: function() {
return this.store.findAll('contact');
}
});
App.IndexRoute = Ember.Route.extend({
model: function(){
return this.store.findAll('product');
}
});
App.ProductsIndexRoute = Ember.Route.extend({
model: function(){
return this.store.findAll('product');
}
});
App.ProductsOnsaleRoute = Ember.Route.extend({
model: function(){
return this.modelFor('products').filterBy('isOnSale');
}
});
App.ProductsDealsRoute = Ember.Route.extend({
model: function(){
return this.modelFor('products').filter(function(product){
return product.get('price') < 500;
});
}
});
App.ProductDetailsComponent = Ember.Component.extend({
reviewsCount: Ember.computed.alias('product.reviews.length'),
hasReviews: function(){
return this.get('reviewsCount') > 0;
}.property('reviewsCount')
});
App.ContactDetailsComponent = Ember.Component.extend({
productsCount: Ember.computed.alias('contact.products.length'),
isProductive: function() {
return this.get('productsCount') > 3;
}.property('productsCount')
});
App.ProductView = Ember.View.extend({
isOnSale: Ember.computed.alias('controller.isOnSale'),
classNameBindings: ['isOnSale']
});
App.ApplicationAdapter = DS.FixtureAdapter.extend();
App.Product = DS.Model.extend({
title: DS.attr('string'),
price: DS.attr('number'),
description: DS.attr('string'),
isOnSale: DS.attr('boolean'),
image: DS.attr('string'),
reviews: DS.hasMany('review', { async: true }),
crafter: DS.belongsTo('contact', { async: true }),
ratings: DS.attr(),
rating: function(){
return this.get('ratings').reduce(function(previousValue, rating) {
return previousValue + rating;
}, 0) / this.get('ratings').length;
}.property('ratings.#each')
});
App.Product.FIXTURES = [
{ id: 1,
title: 'Flint',
price: 99,
description: 'Flint is a hard, sedimentary cryptocrystalline form of the mineral quartz, categorized as a variety of chert.',
isOnSale: true,
image: 'images/products/flint.png',
reviews: [100,101],
crafter: 200,
ratings: [2,1,3,3]
},
{
id: 2,
title: 'Kindling',
price: 249,
description: 'Easily combustible small sticks or twigs used for starting a fire.',
isOnSale: false,
image: 'images/products/kindling.png',
reviews: [],
crafter: 201,
ratings: [2,1,3,3]
},
{
id: 3,
title: 'Matches',
price: 499,
description: 'One end is coated with a material that can be ignited by frictional heat generated by striking the match against a suitable surface.',
isOnSale: true,
reviews: [],
image: 'images/products/matches.png',
crafter: 201,
ratings: [2,1,3,3]
},
{
id: 4,
title: 'Bow Drill',
price: 999,
description: 'The bow drill is an ancient tool. While it was usually used to make fire, it was also used for primitive woodworking and dentistry.',
isOnSale: false,
reviews: [],
image: 'images/products/bow-drill.png',
crafter: 200,
ratings: [1,3,3]
},
{
id: 5,
title: 'Tinder',
price: 499,
description: 'Tinder is easily combustible material used to ignite fires by rudimentary methods.',
isOnSale: true,
reviews: [],
image: 'images/products/tinder.png',
crafter: 201,
ratings: [2,1,3]
},
{
id: 6,
title: 'Birch Bark Shaving',
price: 999,
description: 'Fresh and easily combustable',
isOnSale: true,
reviews: [],
image: 'images/products/birch.png',
crafter: 201,
ratings: [2,3,5]
}
];
App.Contact = DS.Model.extend({
name: DS.attr('string'),
about: DS.attr('string'),
avatar: DS.attr('string'),
products: DS.hasMany('product', { async: true })
});
App.Contact.FIXTURES = [
{
id: 200,
name: 'Giamia',
about: 'Although Giamia came from a humble spark of lightning, he quickly grew to be a great craftsman, providing all the warming instruments needed by those close to him.',
avatar: 'images/contacts/giamia.png',
products: [1,4]
},
{
id: 201,
name: 'Anostagia',
about: 'Knowing there was a need for it, Anostagia drew on her experience and spearheaded the Flint & Flame storefront. In addition to coding the site, she also creates a few products available in the store.',
avatar: 'images/contacts/anostagia.png',
products: [2,3,5,6]
}
];
App.Review = DS.Model.extend({
text: DS.attr('string'),
reviewedAt: DS.attr('date'),
product: DS.belongsTo('product')
});
App.Review.FIXTURES = [
{
id: 100,
text: "Started a fire in no time!"
},
{
id: 101,
text: "Not the brightest flame, but warm!"
}
];
After detailed research, the answer turned out being:
createRating: function() {
var prod = this.get('model');
var ratings = this.get('model.ratings');
ratings.addObject(this.selectedRating);
prod.save();
}
In the code shown, you should be getting the rating using this.get('selectedRating') not this.get('selectedRating.value')
http://emberjs.jsbin.com/xohidixe/1/edit

serialize underscored property ember-data

My serialzer works fine, exept for underscored properties. The sctucture of the JSON from server is:
var services = {
services:[{
id:8,
name:"Codin'",
service_category:{
id:5,
iso_code:"BDT",
prop:"Ohmmmm"
}
},
{
id:7,
name:"PR",
service_category:{
id:2,
iso_code:"SFD",
prop:"Naraya"
}
}]
};
after serialisation the payload looks like this:
var services = {
services:[{
id:8,
name:"Codin'",
service_category:5
},
{
id:7,
name:"PR",
service_category:2
}],
serviceCategories:[{
id:5,
iso_code:"BDT",
prop:"Ohmmmm"
},
{
id:2,
iso_code:"SFD",
prop:"Naraya"
}
]
};
But it in the template i cant access serviceCategory's prop
The models
App.Service = DS.Model.extend({
name: DS.attr('string'),
serviceCategory: DS.belongsTo('serviceCategory')
});
App.ServiceCategory = DS.Model.extend({
iso_code: DS.attr('string'),
prop:DS.attr()
});
Here is the JsBin as usual: http://jsbin.com/OxIDiVU/565
Your json has service_category as the property name in the service.
Easy fix is:
App.Service = DS.Model.extend({
name: DS.attr('string'),
service_category: DS.belongsTo('serviceCategory')
});
and
<td>{{item.service_category.prop}} </td>
http://jsbin.com/OxIDiVU/570/edit

Enyo different collection with same model kind

I have been trying to create two collection with a common model kind. I am getting the following error:
"Uncaught enyo.Store.addRecord: duplicate record added to store for kind app.ImageModel with primaryKey set to id and the same value of 67774271 which cannot coexist for the kind without the ignoreDuplicates flag of the store set to true ".
Following are the two collection i have defined...
enyo.kind({
name: "app.FeatureCollection",
kind: "enyo.Collection",
model: "app.ImageModel",
defaultSource: "appF",
...
...
});
enyo.kind({
name: "app.SearchCollection",
kind: "enyo.Collection",
model: "app.ImageModel",
defaultSource: "appS",
...
...
});
And the model which i am using is as follows:
enyo.kind({
name: "app.ImageModel",
kind: "enyo.Model",
readOnly: true,
....
....
});
At one point i am setting like this:
this.set("data", new app.FeatureCollection());
and in another,
this.set("data", new app.SearchCollection());
I am not able to find out what could generate the error. I even tried to set "ignoreDuplicates" to true in model...but still the error comes. Any suggestion where i could be going wrong.
The ignoreDuplicates flag is expected to be set on enyo.Store and not enyo.Model:
enyo.store.ignoreDuplicates = true;
Are you using the fetch method of enyo.Collection to retrieve your data? If so, you might consider setting the strategy property to merge in your fetch call so that you have a single record for each unique image from your dataset, i.e.:
myCollection.fetch({strategy: "merge", success: function(rec, opts, res) {
// do something after data is retrieved
}});
I'm not seeing a problem with the pieces of code you provided. I created a sample on jsFiddle and it works as expected.
http://jsfiddle.net/z7WwZ/
Maybe the issue is in some other part of your code?
enyo.kind({
name: "app.FeatureCollection",
kind: "enyo.Collection",
model: "app.MyModel"
});
enyo.kind({
name: "app.SearchCollection",
kind: "enyo.Collection",
model: "app.MyModel"
});
enyo.kind({
name: "app.MyModel",
kind: "enyo.Model",
readOnly: true,
defaults: {
firstName: "Unknown",
lastName: "Unknown"
}
});
enyo.kind({
name: "App",
components: [],
bindings: [],
create: enyo.inherit(function (sup) {
return function () {
sup.apply(this, arguments);
this.collection1 = new app.FeatureCollection(this.data1);
enyo.log("Collection1(0) >>> " + this.collection1.at(0).get("lastName"));
this.collection1.at(0).set("lastName", "Smith");
enyo.log("Collection1(0) >>> " + this.collection1.at(0).get("lastName"));
this.collection2 = new app.SearchCollection(this.data2);
enyo.log("Collection2(0) >>> " + this.collection2.at(0).get("lastName"));
this.collection1.at(0).set("lastName", "Jones");
enyo.log("Collection2(0) >>> " + this.collection1.at(0).get("lastName"));
};
}),
data1: [{
firstName: "Hall",
lastName: "Caldwell"
}, {
firstName: "Felicia",
lastName: "Fitzpatrick"
}, {
firstName: "Delgado",
lastName: "Cole"
}],
data2: [{
firstName: "Alejandra",
lastName: "Walsh"
}, {
firstName: "Marquez",
lastName: "James"
}, {
firstName: "Barr",
lastName: "Lott"
}]
});
new App().renderInto(document.body);

Ember Data - Assign a value inside an object

I'm starting up with ember and trying to get some data from an Api and assign it to an Emberjs model.
My api returns something like:
[
{
email: 'someemail#domain.com'
name: {
firstname: 'first name',
lastname: 'last name'
}
}
{
email: 'someemail2#domain.com'
name: {
firstname: 'another first name',
lastname: 'another last name'
}
},
{
email: 'someemail3#domain.com'
name: undefined
}
]
And my code is:
App.Store = DS.Store.extend({
revision: 12,
});
App.Store.registerAdapter('App.Users', DS.Adapter.extend({
findAll: function(store, type, id) {
$.getJSON('https://domain.com/users?callback=?', {
'auth_token': token
}).done(function(json){
store.loadMany(type, json);
});
},
}));
App.Store.registerAdapter('App.Users', DS.Adapter.extend({
findAll: function(store, type, id) {
$.getJSON('https://domain.com/users?callback=?', {
'auth_token': token
}).done(function(json){
store.loadMany(type, json);
});
},
}));
App.Router.map(function() {
this.route("users", { path: "/users" });
});
App.UsersRoute = Ember.Route.extend({
model: function() {
return App.Users.find();
}
});
App.Users = DS.Model.extend({
email: DS.attr('string'),
firstname: DS.attr('string'),
didLoad: function() {
console.log('model loaded', this.toJSON());
}
});
<script type="text/x-handlebars" data-template-name="users">
{{#each model}}
{{email}} - {{firstname}}
{{/each}}
</script>
Obviously firstname is empty for every object in the array.
Does anyone know what's the proper way to do this?
Thanks
Have you tried setting up your User model like this:
App.Adapter.map('App.User', {
name: {embedded: 'always'}
});
App.User = DS.Model.extend({
email: DS.attr('string'),
name: DS.belongsTo('App.UserName')
});
App.UserName = DS.Model.extend({
firstName: DS.attr('string'),
lastName: DS.attr('string')
});

Categories