Sideload with ember - ember.js

Can someone explain why the side loading in this case don't work, I dont get any errors but the followers are not rendered and when I try to check it in the setupController method using model.get('followers').content, I got an empty array.
This is the loaded JSON:
{
user: {
id: 1,
follower_ids: [2,3,4],
name: 'someUserName'
}
followers: [
{
id: 2,
name: 'someUserName'
},
{
id: 3,
name: 'someUserName'
},
{
id: 4,
name: 'someUserName'
}
]
}
and this is my User model
App.User = DS.Model.extend({
name: DS.attr('string'),
followers: DS.hasMany('App.User')
});

Unlike the guide shows, the key for the ids must be followers instead of follower_ids. So with a JSON look like this it works:
{
user: {
id: 1,
followers: [2,3,4],
name: 'someUserName'
}
followers: [
{
id: 2,
name: 'someUserName'
},
{
id: 3,
name: 'someUserName'
},
{
id: 4,
name: 'someUserName'
}
]
}

Related

Buttons: Change value by ID in Ember.js

I‘m trying to have a set of buttons in an {{#each}}<button>...</button>{{/each}} block, and to get the target values by an ID of the model ...
Let’s say there is a controller with model and action:
export default Ember.Component.extend({
Texts: [
{id: "1", name: "One", sample: "Hello!"},
{id: "2", name: "Two", sample: "Hello! Hello!"},
{id: "3", name: "Three", sample: "Hello! Hello! Hello! "},
],
theText: "Test",
actions: {
setText: function(id) {
var theText= this.get('Texts.sample', id);
this.set('theText');
console.log(theText);
}
});
and this in the template:
{{#each Texts as |Text|}}
<button {{action "setText" Text.id}}>{{Text.name}}</button>
{{/each}}
<span>{{theText}}</span>
... this is my idea, but all I get is an undefined ...
Define array properties in init method.
Use findBy method to get matching id row.
export default Ember.Component.extend({
Texts: undefined,
theText: "Test",
init() {
this._super(...arguments);
this.set('Texts', [
{ id: "1", name: "One", sample: "Hello!" },
{ id: "2", name: "Two", sample: "Hello! Hello!" },
{ id: "3", name: "Three", sample: "Hello! Hello! Hello! " },
]);
},
actions: {
setText: function(id) {
let result = this.get('Texts').findBy('id', id);
this.set('theText', result.sample);
console.log(result);
}
}
});

Ember model not displaying field data in template

app/models/index.js
import Model from 'ember-data/model';
import attr from 'ember-data/attr';
export default Model.extend({
title: attr(),
owner: attr(),
city: attr(),
type: attr(),
image: attr(),
bedrooms: attr()
});
app/template/index.hbs
{{#each model as |rental|}}
<p>Location: {{rental.city}}</p>
<p>Number of bedrooms: {{rental.bedrooms}}</p>
{{/each}}
Am returning this from sinatra for the /rentals data request
{ data: [{
id: 1,
title: 'Grand Old Mansion',
owner: 'Veruca Salt',
city: 'San Francisco',
bedrooms: 15,
type: 'rental',
image: 'https://upload.wikimedia.org/wikipedia/commons/c/cb/Crane_estate_(5).jpg'
}, {
id: 2,
title: 'Urban Living',
owner: 'Mike TV',
city: 'Seattle',
bedrooms: 1,
type: 'rental',
image: 'https://upload.wikimedia.org/wikipedia/commons/0/0e/Alfonso_13_Highrise_T egucigalpa.jpg'
}, {
id: 3,
title: 'Downtown Charm',
owner: 'Violet Beauregarde',
city: 'Portland',
bedrooms: 3,
type: 'rental',
image: 'https://upload.wikimedia.org/wikipedia/commons/f/f7/Wheeldon_Apartment_Bu ilding_-_Portland_Oregon.jpg'
}, {
id: 4,
title: 'xDowntown Charm',
owner: 'Violet Beauregarde',
city: 'Portland',
bedrooms: 3,
type: 'rental',
image: 'https://upload.wikimedia.org/wikipedia/commons/f/f7/Wheeldon_Apartment_Building_-_Portland_Oregon.jpg'
}]}.to_json
the each loop knows how many records are there but the field data is missing as the browser shows this
Location:
Number of bedrooms:
Location:
Number of bedrooms:
Location:
Number of bedrooms:
Location:
Number of bedrooms:
Using ember 2.5
Per comment by dynamic_cast I changed the JSON structure to this and got it to work.
{
"data" => [{
"type" => "rentals",
"id" => "1",
"attributes" => {
"title" => 'Grand Old Mansion',
"owner" => 'Veruca Salt',
"city" => 'San Francisco',
"bedrooms" => 15,
"type" => 'rental',
"image" => 'https://upload.wikimedia.org/wikipedia/commons/c/cb/Crane_estate_(5).jpg'
}
},
{
"type" => "rentals",
"id" => "2",
"attributes" => {
"title" => 'Urban Living',
"owner" => 'Mike TV',
"city" => 'Seattle',
"bedrooms" => 1,
"type" => 'rental',
"image" => 'https://upload.wikimedia.org/wikipedia/commons/0/0e/Alfonso_13_Highrise_T egucigalpa.jpg'
}
},
{
"type" => "rentals",
"id" => "3",
"attributes" => {
"title" => 'Downtown Charm',
"owner" => 'Violet Beauregarde',
"city" => 'Portland',
"type" => 'Apartment',
"bedrooms" => 3,
"image" => 'https://upload.wikimedia.org/wikipedia/commons/f/f7/Wheeldon_Apartment_Building_-_Portland_Oregon.jpg'
}
}
]
}.to_json

Displaying data for multi-level relationships with sideloaded json and Ember Data

I have an app that has many layers of relationships. I have a Tournament with n rounds, each round has n matchups, each matchup has n seats, each seat has 1 entry. Here's a sample of the json structure:
{
"tournament": {
"id": 1,
"title": "March Madness!!!",
"rounds": [1],
"active_round": 1
},
"rounds": [
{
"id": 1,
"tournament": 1,
"matchups": [1, 2]
},
{
"id": 2,
"tournament": 1,
"matchups": [3]
}
],
"matchups": [
{ "id": 1, "round": 1, "seats": [1, 2] },
{ "id": 2, "round": 1, "seats": [3, 4] },
{ "id": 3, "round": 2, "seats": [5, 6] }
],
"seats": [
{ "id": 1, "matchup": 1, "entry": 1 },
{ "id": 2, "matchup": 1, "entry": 2 },
{ "id": 3, "matchup": 2, "entry": 3 },
{ "id": 4, "matchup": 2, "entry": 4 },
{ "id": 5, "matchup": 3, "entry": "" },
{ "id": 6, "matchup": 3, "entry": "" }
],
"entries": [
{
"id": 1,
"seats": [1]
},
{
"id": 2,
"seats": [2]
},
{
"id": 3,
"seats": [3]
},
{
"id": 4,
"seats": [4]
}
]
}
I'm having trouble getting the content out. Here's my router.js:
App.Router.map( function() {
this.resource('tournament', { path: "/" });
});
App.TournamentRoute = Ember.Route.extend({
model: function() {
return new Ember.RSVP.Promise( function (resolve, reject) {
[..we just get the data return the json object above to setupController...]
});
},
setupController: function (controller, model) {
controller.set('model', model);
[i do a little data computation here prior to the renderTemplate function]
},
renderTemplate: function () {
var controller = this.controllerFor('tournament');
this.render('tournament');
}
});
My tournament.hbs template looks like this:
<h1>{{tournament.title}}</h1>
{{#each round in rounds}} Round id: {{round.id}} <br/>
{{#each matchup in round.matchups}} matchup id: {{matchup.id}}
<div class="matchup">
{{#each seat in matchup.seats}}
<div class="entry">
{{seat.entry.id}}
</div>
{{/each}}
</div>
{{/each}}
{{/each}}
And I'm getting the following on screen:
March Madness!!!
Round id: 1
matchup id:
matchup id:
Round id: 2
matchup id:
So, a little bit of it is working. I've done some work in the console and at the matchup level, the matchup object is actually the values "1" and "2", not matchups[0] and matchups[1], as expected, which is why there is no "id" attribute next to the matchup levels. I'm not sure how much "magic" there is in Ember data by using conventions, and can't find any examples that use this level of hierarchy. Thanks
UPDATE:
I'm including my models so as they are now, with the first responder's recommendations. I'm seeing the same results.
App.Tournament = DS.Model.extend({
title: DS.attr('string'),
active_round_index: DS.attr('number'),
rounds: DS.hasMany('App.Round', { embedded: 'always' })
});
App.Round = DS.Model.extend({
tournament: DS.belongsTo('App.Tournament'),
matchups: DS.hasMany('App.Matchup', { embedded: 'always' })
});
App.Matchup = DS.Model.extend({
round: DS.belongsTo('App.Round'),
seats: DS.hasMany('App.Seat', { embedded: 'always' })
});
App.Seat = DS.Model.extend({
matchup: DS.belongsTo('App.Matchup'),
entries: DS.hasMany('App.Entry', { embedded: 'always' })
});
App.Entry = DS.Model.extend({
title: DS.attr('string'),
seats: DS.hasMany('App.Seat')
});
** ANOTHER UPDATE **
So, as it turns out, the documented usage of the Ember.RSVP.Promise won't use all of the "magic" of Ember Data, which needs the RESTAdapter to do the fanciness. I plugged in the RESTAdapter and now things are working much better.
I can't see what your models look like, but one problem could be that you don't have the hasMany relationship definitions on your model marked as {embedded: 'always'}. This tells the ember serializer how to handle your related models when serializing and extracting.
example:
App.Round = DS.Model.extend({
tournament: DS.belongsTo('tournament'),
matchups: DS.hasMany('matchup', { embedded: 'always' })
});

Sideload a lists "belongsTo" objects with EmberData

I have 3 emberData models:
App.Product = DS.Model.extend({
page_title: DS.attr('string'),
shop: DS.belongsTo('App.Shop'),
user: DS.belongsTo('App.User')
});
App.Shop = DS.Model.extend({
name: DS.attr('string'),
});
App.User = DS.Model.extend({
name: DS.attr('string')
});
and the JSON data looks like this:
{
products: [
{
id: "1",
page_title: "Product 1",
user_id: "1",
shop_id: "1",
},
{
id: "2",
page_title: "Product 2",
user_id: "2",
shop_id: "1",
}
],
users: [
{
id: "1",
name: "User 1"
},
{
id: "2",
name: "User 2"
}
],
shops: [
{
id: "1",
name: "Shop 1"
}
]
}
But when I load the data I got the following error:
Assertion failed: Your server returned a hash with the key shops but you have no mapping for it
Ok, the documentaion is very unclear about the fact that when you have a belongsTo relationship the key for the sideload must be singular not plural even if its a list. So the JSON has to look like this:
{
products: [
{
id: "1",
page_title: "Product 1",
user_id: "1",
shop_id: "1",
},
{
id: "2",
page_title: "Product 2",
user_id: "2",
shop_id: "1",
}
],
user: [
{
id: "1",
name: "User 1"
},
{
id: "2",
name: "User 2"
}
],
shop: [
{
id: "1",
name: "Shop 1"
}
]
}

How to sideload ember hasMany and belongsTo Relationship?

I have a Person Model as follows
App.Person= DS.Model.extend({
id: DS.attr('string'),
name: DS.attr('string'),
visits: DS.hasMany('App.Visit'),
events: DS.hasMany('App.Event') ,
allergies: DS.hasMany('App.Allergies'),
get_allergies : function(){
return this.get('allergies').getEach('allergy_name').reduce(function(accum, item) {
return (accum.length > 0) ? (accum +', '+ item) : (item);
}, '');
}.property('allergies.#each.allergy_name')
});
App.Visit = DS.Model.extend({
visit_id: DS.attr('string'),
date: DS.attr('date'),
admission: DS.belongsTo('App.Admission')
});
App.Admission = DS.Model.extend({
loc: DS.attr('string'),
admission_date: DS.attr('date'),
care_team: DS.belongsTo('App.CareTeam')
});
As you can see Person hasMany "allergies", and along with person, allergies is also getting loaded for me because in the UI I am calling the get_allergies method while other hasMany relationships like "visits" and "events" are not getting loaded.
In UI {{person.get_allergies}}
I tried to sideload the relationships "visits" and "events"(using example on net), but that is not working? Can someone tell what is the proper way of sideloading ember-data because I couldnt find any proper documention with example on net except for few questions on stackoverflow itself?
According to the documentation, you should just add additional Visit and Event data in the response from the server.
{
"person": {
"id": 1,
...
"event_ids": [5, 6, 7]
},
"events": [{
"id": 5,
...
},
{
"id": 6,
...
},
{
"id": 7,
...
}]
}
The main point here is that Events data should be outside of Person data.
Do you use the standard REST adapter? Could you please add a sample json returned by the server?
To sideload data in my app, I configure ember-data to know about the kinds of things I'll be sideloading. E.g. to sideload events and visits, do this:
DS.RESTAdapter.configure('App.Event', {
sideloadsAs: 'events'
});
DS.RESTAdapter.configure('App.Visit', {
sideloadsAs: 'visits'
});
App.Store = DS.Store.extend({
revision: 11
});
and then in your json can look like this:
{
"person": {
"id": 1,
"event_ids": [5, 6, 7],
"visit_ids": [1, 2, 3]
},
"events": [
{ "id": 5 },
{ "id": 6 },
{ "id": 7 }
],
"visits": [
{ "id": 1 },
{ "id": 2 },
{ "id": 3 }
]
}
I had the same problem but set up a bit different. visits were unaware of their person (i.e. couldn't do visit.get('person.name')). I had to add a serializer for visit:
export default AppSerializer.extend({
attrs: {
person: 'personId'
},
});
My payload looks like this:
{
person: {
id: 1,
name: 'John',
visitIds: [1, 2, 3]
},
visits: [
{ id: 1,
personId: 1
},
{ id: 2,
personId: 1
},
{ id: 3,
personId: 1
}
]
}
person model:
export default DS.Model.extend({
name: DS.attr('string'),
visits: DS.hasMany('visit')
});
visit model:
export default DS.Model.extend({
person: DS.belongsTo('person')
});