ember how to display relationship property in template - ember.js

I have a ember data model like this:
var attr = DS.attr,
hasMany = DS.hasMany,
belongsTo = DS.belongsTo;
App.Message = DS.Model.extend({
partner_pk: attr(),
message: attr(),
user: belongsTo('user', {async: true}),
inquiry: belongsTo('inquiry', {async: true}),
created_at: attr(),
updated_at: attr()
});
and route returning array of data like this:
App.TripMessagesRoute = Ember.Route.extend({
model: function(){
return this.store.find('message', {inquiry_id: 2});
}
})
My rest-api return data like this format:
{
"data": [
{
"id": 10,
"message": "this message is updated by ember.js",
"inquiry_id": 2,
"user_id": 1,
"created_at": "2014-08-05 14:20:46",
"updated_at": "2014-08-05 14:20:46"
},
{
"id": 17,
"message": "this is a test message by ember.js",
"inquiry_id": 2,
"user_id": 39,
"created_at": "2014-08-26 17:34:55",
}
]
}
in my template I am displaying the properties like this:
<script type="text/x-handlebars" data-template-name="trip/messages">
<h2>message is: {{message}}</h2> <!-- This works fine -->
<h2>User id: {{log user}}</h2> <!-- it gives null -->
<h2>User id: {{log user_id}}</h2> <!-- it gives undefined -->
</script>
My question is how do I display user_id in my template. Thanks in advance.

By default the property name in your Model definition should match the property being returned in your JSON.
Your choices are...
change your model to look like user_id: belongsTo('user', {async: true})
change your JSON to look like "user_id": 39
Add a MessageSerializer and change the object from user_id to user in the serializer.
You should then be able to put something like {{user.id}} in your template.

Related

ember-data relationships not working

Trying to figure out how to use relationships and it just is not working.
// Data
{
"apps": {
"-AFCH5-Kvkc_nfQxnpZ8": {
"name": "Leap Day",
"playLink": "https://play.google.com/store/apps/details?id=com.nitrome.leapday",
"price": "0.00",
"like": 0,
"show": "-SFCH5-Kvkc_nfQxnpZ8",
"provider": "-PFCH5-Kvkc_nfQxnpZ8",
"imageUrl": "https://www.google.com/url?q=https://lh3.googleusercontent.com/5oR-jbrmKNWqdWQnwrDjPD2PJUJekGK_BUAQOjKD3GuJRTk2MLVzuU2HJ0wyY2BYPsdS%3Dw300-rw&sa=D&ust=1464126095843000&usg=AFQjCNH0RSH6_0bA_EUqnZaldtUxCH1fAw"
},
"-AFCH5-Kvkc_nfQxnpZ9": {
"name": "Gangfort",
"playLink": "https://www.google.com/url?q=https://play.google.com/store/apps/details?id%3Dcom.gangfort.game.android&sa=D&ust=1464126095844000&usg=AFQjCNFSTZ1p_uBvIHYw97c29XwJU3gEjw",
"price": "1.99",
"like": 0,
"show": "-SFCH5-Kvkc_nfQxnpZ8",
"provider": "-PFCH5-Kvkc_nfQxnpZ8",
"imageUrl": "https://www.google.com/url?q=https://lh3.googleusercontent.com/DV5mFhDQ2ADEbiF0S4cxL313JDqRazy9et7Etky5WtH7gxsm9DvbHhb52N0MH1swgfzR%3Dw300-rw&sa=D&ust=1464126095844000&usg=AFQjCNEymzxjrdN8wwL4qN40w5i8i9MlPw"
}
},
"shows": {
"-SFCH5-Kvkc_nfQxnpZ8": {
"number": 432,
"name": "Google I/O Secrets Revealed",
"date": "05/22/2016",
"app": ["-AFCH5-Kvkc_nfQxnpZ8", "-AFCH5-Kvkc_nfQxnpZ9"],
"url": "http://podnutz.com/aaa432/"
}
},
"providers": {
"-PFCH5-Kvkc_nfQxnpZ8": {
"firstName": "Steve",
"lastName": "McLaughlin",
"nick": "D2d",
"app": ["-AFCH5-Kvkc_nfQxnpZ8", "-AFCH5-Kvkc_nfQxnpZ9"]
}
}
}
Here is the app model
import Model from 'ember-data/model';
import attr from 'ember-data/attr';
import { belongsTo } from 'ember-data/relationships';
export default Model.extend({
name: attr('string'),
playLink: attr('string'),
price: attr('string'),
like: attr('number'),
show: belongsTo('show', {
async: true
}),
provider: belongsTo('provider', {
async: true
}),
imageUrl: attr('string')
});
Here is the show model
import Model from 'ember-data/model';
import attr from 'ember-data/attr';
import { hasMany } from 'ember-data/relationships';
export default Model.extend({
number: attr('number'),
name: attr('string'),
date: attr('date'),
apps: hasMany('app'),
url: attr('string')
});
Here is my route
import Ember from 'ember';
export default Ember.Route.extend({
model() {
return this.store.findAll('app');
}
});
Here is what the ember console looks like
So the problem is when I try to access the show object in my template, its not coming up
{{#each model as |show|}}
{{app.show.name}}
{{/each}}
Update
From the looks of the markup it seems like something is working here
Here is the console when I log app.show
Looks like apps: hasMany('app') reference in your show model is overwriting your relationship defined in the shows model.
you are not iterating through each app model in template.
it should be like that
{{#each model as |app|}}
{{app.show.name}}
{{/each}}
your each loop is like that {{#each model as |show|}}
Try this:
{{#each model as |app|}}
{{#if app.show}}
{{app.show.name}}
{{/if}}
{{else}}
Loading apps...
{{/each}}
Here I would recommend taking advantage of ember-promise helpers since the relation between an app and a show is asynchronous:
{{#each model as |app}}
{{#if (await app.show)}}
{{get (await app.show) 'name'}}
{{/if}}
{{else}}
Loading apps...
{{/each}}

How to save changes on associated models in Ember Data

I'm running Ember Data 1.0.0 with Ember 1.3.0.
I have this data:
{
"product": {
"id": 185588,
"name": "USB MIDI Adapter",
"images":["imageid1", "imageid2"....]
},
"images": [
{
"id": "imageid1",
"url": "google.com"
},
{
"id": "imageid2",
"url": "google.com2"
}
]
}
And these models:
App.Image = DS.Model.extend({
url: DS.attr('string')
});
App.Product = DS.Model.extend({
name: DS.attr('string'),
images: DS.hasMany('Image')
});
In my template I have an edit form to change the url on the associated images:
<form {{action save on="submit"}}>
{{input type="text" value=name}}
{{#each images}}
* {{input type="text" value=url}}<br>
{{/each}}
<button type="submit">Save</button>
</form>
The save action is:
save: function() {
var product = this.modelFor('productEdit');
product.save();
this.transitionTo('product', product);
}
The problem is that the save action only saves the product (PUT product), but not the changed that's made to the image urls. The model binding works fine, when I change the url on images the gui is updated as it should, but the PUT is not sent as it should.
How do I save the image changes?
You either need to call save on each record, call save on the recordarray(which will iterate and save), or you can override the serializer (serializeIntoHash) to inject the images into the save of the product.
records.forEach(function(record){
if(record.get('isDirty')) record.save();
});

Ember data alias model / Map JSON response

My server returns a JSON response like this:
{
artists: [{
id: "1",
first_name: "Foo",
last_name: "Bar"
}],
studios: [{
id: 1,
name: "Test",
// ...
artist_ids: ["1"]
}]
}
'artist' is in fact a User model but with a different name. How can I map artist to the User model? Maybe a bad explanation but if I rename the JSON response serverside to 'users' instead of 'artist' and use the models below everything works like I want. I simply want to use the name 'artist' instead of 'user', both server side and client side. Hope you guys understand what i mean.
App.Studio = DS.Model.extend
name: DS.attr 'string'
// ..
users: DS.hasMany 'App.User'
App.User = DS.Model.extend
firstName: DS.attr 'string'
lastName: DS.attr 'string'
studio: DS.belongsTo 'App.Studio'
I guess that the simplest thing to do would be something like artists: DS.hasMany 'App.User' but obviously this does not work.
First, I recommend using the latest Ember / EmberData, so relationships are defined like this:
App.Studio = DS.Model.extend({
name: DS.attr('string'),
// ..
users: DS.hasMany('user')
});
App.User = DS.Model.extend({
firstName: DS.attr('string'),
lastName: DS.attr('string'),
studio: DS.belongsTo('studio')
});
Next, I recommend using the ActiveModelAdapter if you are getting underscores in your response JSON:
App.ApplicationAdapter = DS.ActiveModelAdapter;
Finally, overriding typeForRoot and keyForRelationship in a custom serializer should fix your issue:
App.ApplicationSerializer = DS.ActiveModelSerializer.extend({
typeForRoot: function(root) {
if (root == 'artist' || root == 'artists') { root = 'user'; }
return this._super(root);
},
keyForRelationship: function(key, kind) {
if (key == 'users') { key = 'artists'; }
return this._super(key, kind);
}
});
Example JSBin
One last thing: you can even get rid of the custom keyForRelationship if you name the relationship artists in Studio:
App.Studio = DS.Model.extend({
name: DS.attr('string'),
// ..
artists: DS.hasMany('user')
});
Have you tried just creating an Artist model extended from User?
App.Artist = App.User.extend({})
I haven't tried it, but I suspect that might work.

Create an associated model from JSON

I have a server response that looks like:
comments: [
0: {
body: "test3",
created_at: "2013-06-27T22:27:47Z",
user: {
email: "test#test.com",
id: 1,
name: "Tester"
}
}
]
And ember models:
App.Comment = DS.Model.extend({
user: DS.belongsTo('App.User'),
body: DS.attr('string')
});
App.User = DS.Model.extend({
name: DS.attr('string'),
email: DS.attr('string'),
});
How do I create an ember user model from the server's response?
The solution if you're using rails active model serializers is to embed :ids, include: true:
app/serializers/comment_serializer.rb
class CommentSerializer < ActiveModel::Serializer
embed :ids, include: true
attributes :created_at, :body
has_one :user
end
Just like the readme for active_model_serializers says, this will produce:
{
"users":[
{
"id":1,
"name":"Tester",
"email":"test#test.com",
}
],
"comments":[
{
"event":"commented",
"created_at":"2013-06-27T22:27:47Z",
"body":"test3",
"user_id":1
}
]
}

Ember Data, Relationships, output of attribute

I have two entities with fixtures data: User and Role. When I load a User, it contains one Role. I would like to show the name of the role. Here is relevant code:
App.User = DS.Model.extend({
name: DS.attr('string'),
role: DS.belongsTo('App.Role'),
});
App.Role = DS.Model.extend({
name: DS.attr('string'),
});
App.User.FIXTURES = [{
id:1,
name:'user',
role:1
}];
App.Role.FIXTURES = [{
id:1,
name:'reader',
}]
App.UsersRoute = Ember.Route.extend({
model: function() {
return App.User.find();
}
});
<script type="text/x-handlebars" data-template-name="users">
{{#each controller}}
{{name}} {{role.name}}
{{/each}}
</script>
the name of role is not displayed but if I change it to {{role.id}} the id of role is displayed
i think you may need to add
users: DS.hasMany('App.User')
to the definition of your Role model.