How to load dependencies in Ember Data - ember.js

I have an application, with 2 models: Team and User. Each team has many users, and only 1 Team Leader. On the Index view for Teams, I want to display the list of Teams, and the name of the Team leader. I can't get the name of the team leader to be displayed. Not sure what's wrong.
User Model:
export default Model.extend({
firstName: attr(),
lastName: attr(),
team: belongsTo('team', { inverse: 'users' }),
fullName: Ember.computed('firstName', 'lastName', function() {
return `${this.get('firstName')} ${this.get('lastName')}`;
})
});
Team Model:
export default Model.extend(Validations, {
name: attr(),
shortName: attr(),
description: attr(),
teamLeader: belongsTo('user', { inverse: null }),
users: hasMany('user'),
specialisationArea: attr(),
sourceEnergyTeam: attr(),
isEnergyTeam: Ember.computed('specialisationArea', function(){
return this.get('specialisationArea') == 101;
})
});
Team Index Route:
export default Ember.Route.extend({
model() {
return this.store.findAll('team');
}
});
Team List Template:
{{#each model as |team|}}
<tr>
<td>{{team.name}}</td>
<td>{{team.shortName}}</td>
<td>{{team.description}}</td>
<td>{{team.teamLeader.fullName }}</td>
<td>{{#link-to "teams.team" team}}Details{{/link-to}}</td>
</tr>
{{/each}}
And this is the mirage configuration:
this.get('/teams', () => {
return [{
id : 11,
type: 'team',
name: 'Energy',
description: 'energy desc',
shortName: 'short',
teamLeader: 12,
users: [12],
energyTeam: true
}];
});
this.get('/teams/:team_id', () => {
return {
id: 11,
type: 'team',
name: 'energy',
description: 'energy desc',
shortName: 'eg',
teamLeader: 12,
users: [12],
energyTeam: true
};
});
this.get('/users', () => {
return [{
id: 12,
type: 'user',
firstName: 'Pedro',
lastName: 'Alonso',
team: 11
}];
});
I'm not sure what's going wrong, but in the network calls I can see that only a call to '/teams' is being triggered. Any ideas?
Thanks

Related

Ember self-reference and polymorphism

there is a user model which also relates to itself as contact so user has_many contacts.
Than each contact has and belongs to many "groups". Both user and contact has one address.
I read through http://lukegalea.github.io/ember_data_polymorphic_presentation/#/ couple of times, but yet still do no understand how to setup { user | contact } <-> address relationship and a contacts <-> groups association on the Ember side.
Right now I have (a simplified representation):
// Address
export default DS.Model.extend({
city: DS.attr('string'),
profile : DS.belongsTo('profile', { polymorphic: true, async: true })
});
// Profile
export default DS.Model.extend({
name: DS.attr('string'),
phone: DS.attr('string'),
address: DS.belongsTo('address', {async: true})
});
// Contact
export default Profile.extend({
groups: DS.hasMany('group')
});
// User
export default Profile.extend({
});
Here is the JSON
// GET /contacts
{
"contacts":[
{
"name":"Conrad",
"address_id":"1",
"id":1
},
{
"name":"Greyson",
"address_id":"2",
"id":2
},
{
"name":"Tommie",
"address_id":"3",
"id":3
}
]
}
// GET /addresses
{
"addresses":[
{
"city":"West Lillaton",
"profile_id":"0",
"profile_type":"Contact",
"id":1
},
{
"city":"Weissnatborough",
"profile_id":"1",
"profile_type":"Contact",
"id":2
},
{
"city":"Predovicton",
"profile_id":"2",
"profile_type":"Contact",
"id":3
},
{
"city":"VKHA",
"profile_id":1,
"profile_type":"User",
"id":4
}
]
}
// GET /users
{
"users":[
{
"name":"Emile",
"address_id":4,
"id":1
}
]
}
As far as I understand there is no need in polymorphic here, because you wrote: "user model which also relates to itself". You should set reflexive relation contacts for user model.
When you want to define a reflexive relation, you must either explicitly define the other side, and set the explicit inverse accordingly, and if you don't need the other side, set the inverse to null.
http://guides.emberjs.com/v1.12.0/models/defining-models/#toc_reflexive-relation
// User
export default DS.Model.extend({
name: DS.attr('string'),
phone: DS.attr('string'),
address: DS.belongsTo('address', {async: true, inverse: 'user'})
groups: DS.hasMany('group', {async: true}),
contacts: DS.hasMany('user', { inverse: null }),
});
// Address
export default DS.Model.extend({
city: DS.attr('string'),
user: DS.belongsTo('user', { async: true, inverse: 'address' })
});
// Group
export default DS.Model.extend({
name: DS.attr('string'),
users: DS.hasMany('user', {async: true}),
});
If you'd like user and contact to be different ember models then
address belongsTo polymorphic profile:
// Profile
export default DS.Model.extend({
name: DS.attr('string'),
phone: DS.attr('string'),
address: DS.belongsTo('address', {async: true, inverse: 'profile'})
});
// Contact
export default Profile.extend({
groups: DS.hasMany('group', {async: true}),
user: DS.belongsTo('user', { async: true, inverse: 'contacts' })
});
// User
export default Profile.extend({
contacts: DS.hasMany('contact', { inverse: 'user' }),
});
// Address
export default DS.Model.extend({
city: DS.attr('string'),
profile: DS.belongsTo('profile', { polymorphic: true, async: true, inverse: 'address' })
});
// Group
export default DS.Model.extend({
name: DS.attr('string'),
contacts: DS.hasMany('contact', {async: true}),
});
Note: proper paylod for GET addresses should be :
// GET /addresses
{"addresses":[
{
"id":1,
"city":"West Lillaton",
"profile": {"id:"1", "type":"Contact"},
},{
"id":2,
"city":"West Lillaton",
"profile": {"id:"2", "type":"User"},
}
]}

Ember model find records without server request

I have an ember model Category:
export default DS.Model.extend({
name: DS.attr('string'),
img: DS.attr('string'),
url: DS.attr('string'),
cnt: DS.attr('number'),
// parent_id: DS.belongsTo('category', {
// inverse: 'children',
// async: true
// }),
parent_id: DS.attr('string'),
// children: DS.hasMany('category', {
// inverse: 'parent_id',
// async: true
// }),
children: DS.attr(),
isSelected: false,
isExpanded: false,
hasChildren: function() {
return this.get('children').get('length') > 0;
}.property('children').cacheable(),
isLeaf: function() {
return this.get('children').get('length') == 0;
}.property('children').cacheable()
});
In my index route I have:
export default Ember.Route.extend({
model: function() {
var store = this.store;
return Ember.ArrayProxy.create({
categories: store.find('category'),
menuTopCategories: store.find('category', { parent_id: 1 })
});
}
});
I'm using a RESTAdapter so the store.find will send two requests to the server: categories and categories?parent_id=1.
I would like to have only the first request and then filter through the categories. I tried store.all - since I saw it reuses the already fetch data, but I can't manage to apply the filter.
I've rewritten the menuTopCategories and I don't see a new request:
menuTopCategories: store.filter('category', function(category) {
return category.get('parent_id') === "1";
})
My problem right now is to get the root category (first one) without hardcoding the parent_id.

ember data only with a belongsto relationship

here is a working jsbin: http://emberjs.jsbin.com/EnOqUxe/71/edit
What i´d like to have is there the company doesn´t need any reference to the person.
non working code
App.Company.FIXTURES = [
{ id: 1, name: 'Microsoft'},
{ id: 2, name: 'Apple'}
];
App.Person.FIXTURES = [
{ id: 1, name: 'Steve Jobs', company:2},
{ id: 2, name: 'Bill Gates', company:1},
{ id: 3, name: 'Steve Ballmer', company:1}
];
How can i achieve this?
thank you
You're practically there. You just need to fix up the models a bit:
App.Company = DS.Model.extend({
name: DS.attr('string')
});
App.Person = DS.Model.extend({
name: DS.attr('string'),
company: DS.belongsTo('company', {async:true})
});
And change your model hook, since now you link to companies through people, not people through companies.
App.IndexRoute = Ember.Route.extend({
model: function() {
return this.store.find('person');
}
});
http://emberjs.jsbin.com/EnOqUxe/72/edit

createRecord with ember-data + ember-data-django-rest-adapter

I'm currently working on creating an ember application using ember/ember-data/ember-data-django-rest-adapter with Django backend.
I'm having issue creating record when there's belongsTo and hasMany relationship going on.
I currently have this code:
App.Article = DS.Model.extend({
title: attr(),
description: attr(),
authors: hasMany('author'),
category: belongsTo('page'),
slug: attr(),
content: attr(),
articleContent: Ember.computed.alias("content"),
published: attr(),
publish_from: attr(),
isScheduled: function() {
return moment().isBefore(moment(this.get('publish_from')));
}.property('publish_from'),
articlePublishDate: function() {
return moment(this.get('publish_from')).format('MMMM Do YYYY');
}.property('publish_from'),
articlePublishTime: function() {
return moment(this.get('publish_from')).format('h:mm a');
}.property('publish_from'),
//content_type: belongsTo('content_type', { async: true }),
content_type: attr()
});
App.Page = DS.Model.extend({
title: attr(),
description: attr(),
pageContent: attr(null, {
key: 'content'
}),
templateFile: attr(null, {
key: 'template'
}),
slug: attr(),
tree_path: attr(),
tree_parent: belongsTo('page'),
site: attr()
});
App.Author = DS.Model.extend({
name: attr(),
slug: attr(),
description: attr(),
text: attr(),
email: attr(),
photo: attr(),
user: belongsTo('user'),
});
// create article
App.ArticleCreateController = Ember.ObjectController.extend({
editMode: false,
allAuthors: function() {
return this.store.find('author');
}.property(),
allPages: function() {
return this.store.find('page');
}.property(),
actions: {
save: function(session) {
var self = this;
var article = this.get('model');
var newArticle = this.store.createRecord('article', {
content_type: "19",
content: article.get('articleContent'),
description: article.get('description'),
publish_from: article.get('publish_from'),
published: article.get('published'),
slug: article.get('slug'),
title: article.get('title')
});
this.store.find('page', 3).then(function(page) {
newArticle.set('category', page);
});
newArticle.save();
}
}
});
All I really want to do is POST data like this to apiRoot/articles/ (along with other attributes, but those are working the way they should)
authors: [1,3,5], // hasMany
category: 3 // belongsTo
But when I make a POST request, category returns as null for some reason. All I want to extract from it is just the id itself. Also, I have no clue how to extract the array of authors. I tried posting the data, and it tells me something about it needing to be 'App.Author'.
First, at the current time you need a fork of ember-data because async create is currently broken (as it's a promise and the internal serializer won't wait for it to resolve).
Pull down this branch, do a npm install + grunt test to build the adapter. Also you need to use the forked build of ember-data in that branch'es test lib directory (until ember-data pulls in the fix for this)
https://github.com/toranb/ember-data-django-rest-adapter/tree/asyncBelongsToHasManyWIP
Then inside your controller you can do something like this to "create" the customer and appointment (notice -async belongsTo/hasMany relationship)
App.Customer = DS.Model.extend({
name: DS.attr('string'),
appointments: DS.hasMany('appointment', { async: true})
});
App.Appointment = DS.Model.extend({
details: DS.attr('string'),
customer: DS.belongsTo('customer', { async: true})
});
var customer = {
name: 'foobar'
}
this.store.createRecord('customer', customer).save().then(function(persisted) {
var appointment = {
details: 'test',
customer: persisted
}
return self.store.createRecord('appointment', appointment).save().then(function(apt) {
persisted.get('data').appointments.pushObject(apt);
router.transitionTo('index');
});
});

ember Uncaught Error: assertion failed: Emptying a view in the inBuffer state

I get this assertion when run the code below:
Emptying a view in the inBuffer state is not allowed and should not
happen under normal circumstances. Most likely there is a bug in your
application. This may be due to excessive property change
notifications.
Link to demo:
http://plnkr.co/edit/s3bUw4JFrJvsL690QUMi
var App = Ember.Application.create({
Store: DS.Store.extend({
revision: 4,
adapter: DS.FixtureAdapter.create()
}),
Router: Ember.Router.extend({
root: Ember.Route.extend({
index: Ember.Route.extend({
route: "/",
connectOutlets: function(router){
var person;
person = App.Person.find(657);
person.addObserver("isLoaded", function() {
return router.get('router.applicationController').connectOutlet("things", person.get("things"));
});
}
})
})
}),
ApplicationController: Em.Controller.extend(),
ApplicationView: Em.View.extend({
template: Em.Handlebars.compile("{{outlet}}")
}),
ThingsController: Em.ArrayController.extend({
thingTypes: (function() {
return App.ThingType.find();
}).property()
}),
ThingsView: Em.View.extend({
template: Em.Handlebars.compile([
'{{#each controller.thingTypes}}',
'{{this.name}}',
'{{/each}}',
'{{#each controller.content}}',
'{{this.title}}',
'{{/each}}'].join(""))
}),
//MODELS
Person: DS.Model.extend({
things: DS.hasMany('App.Thing', {
embedded: true
})
}),
Thing: DS.Model.extend({
description: DS.attr('string'),
thingType: DS.belongsTo("App.ThingType", {
embedded: true
}),
title: (function() {
return this.get("thingType.name");
}).property("description")
}),
ThingType: DS.Model.extend({
name: DS.attr("string")
})
});
App.Person.FIXTURES = [
{
id: 657,
things: [
{
id: 1,
description: "Some text",
thing_type: {
id: 1,
name: "type 1"
}
}, {
id: 2,
description: "Some text",
thing_type: {
id: 2,
name: "type 2"
}
}
]
}
];
App.ThingType.FIXTURES = [
{
id: 1,
name: "type 1"
}, {
id: 2,
name: "type 2"
}, {
id: 3,
name: "type 3"
}
];
Why is this happening?
I was having the same error while trying to load a list of dropdown values from fixtures. What resolved it was overriding queryFixtures on the fixture adapter:
App.FixtureAdapter = DS.FixtureAdapter.extend
latency: 200
queryFixtures: (records, query, type) ->
records.filter (record) ->
for key of query
continue unless query.hasOwnProperty(key)
value = query[key]
return false if record[key] isnt value
true
I probably wouldn't have figured it out had I not set the latency first. Then the error was a bit more descriptive.
a bit late I guess... but I got it to work here:
http://plnkr.co/edit/hDCT4Qy1h5aE6GjM76qp
Didn't change the logic but where its called
I modified your router like this:
Router: Ember.Router.extend({
root: Ember.Route.extend({
index: Ember.Route.extend({
route: "/",
connectOutlets: function(router) {
var person;
router.set('router.applicationController.currentPerson', App.Person.find(657));
}
})
})
})
And created an ApplicationController:
ApplicationController: Em.Controller.extend({
currentPerson: null,
currentPersonLoaded: function() {
this.connectOutlet("things", this.get("currentPerson.things"));
}.observes("currentPerson.isLoaded"),
})
I dont know if this is the output you wished but the bug vanished!