How can I get the associated record from an Ember model? Or: how to get the record from the Promise Object?
Customer model
Docket.Customer = DS.Model.extend({
name: DS.attr('string'),
initial: DS.attr('string'),
description: DS.attr('string'),
number: DS.attr('string'),
archived: DS.attr('boolean'),
projects: DS.hasMany('project',{ async: true })
});
Project model
Docket.Project = DS.Model.extend({
name: DS.attr('string'),
description: DS.attr('string'),
number: DS.attr('string'),
archived: DS.attr('boolean'),
customer: DS.belongsTo('customer', { async: true })
});
Find method
var project = this.store.find('project', id).then(function(data) {
console.log(data.get('customer').toString());
});
Console output
<DS.PromiseObject:ember654>
JSON response
{"projects":[
{
"id":1,
"name":"test",
"number":"a310",
"description":null,
"archived":false,
"customer_id":22
}
]};
use another then on the get :)
var project = this.store.find('project', id).then(function(data) {
data.get('customer').then(function(c){
console.log(c);
}
});
Related
I am a newbie on Ember and break my head already a couple of hours how i can use the value of a model field in a controller ?
This is my model :
import DS from 'ember-data';
export default DS.Model.extend({
id_customer: DS.attr('number'),
id_default_group: DS.attr('number'),
id_lang: DS.attr('number'),
id_gender: DS.attr('number'),
active: DS.attr('boolean'),
email: DS.attr(),
firstname: DS.attr(),
lastname: DS.attr(),
company: DS.attr(),
birthday: DS.attr('date'),
date_add: DS.attr('date'),
date_upd: DS.attr('date'),
max_payment_days: DS.attr('number'),
newsletter: DS.attr('boolean'),
note: DS.attr(),
website: DS.attr()
});
This is my route :
import Ember from 'ember';
export default Ember.Route.extend({
beforeModel: function(){
if(!this.get('session.isAuthenticated')){
this.transitionTo('application');
}
},
model(params) {
return Ember.RSVP.hash({
customer: this.store.findRecord('customer', params.id),
address: this.store.query('address', {
orderBy: 'id_customer_fb',
equalTo: parseInt(params.id)
})
});
}
});
This is my controller :
import Ember from 'ember';
const genders = [
{ title: 'Dhr.', id_gender: '1' },
{ title: 'Mevr.', id_gender: '2' },
];
export default Ember.Controller.extend({
genders: genders,
selection: genders[1]**, <== THIS '1' MUST BE REPLACED WITH THE VALUE OF models.customer.id_gender ?????**
actions: {
chooseDestination(genders) {
this.set('selection', genders);
},
}
});
I would that the value 1 in this genders array could be the value of model.customer.id_gender ?
Yes you can.
Change selection like this :
selection: Ember.computed(function(){
let ret = this.get('genders').filterBy('id_gender', this.get('model.customer.id_gender'));
return ret.objectAt(0);
})
Please take a look at this twiddle
Below is a basic ember model:
App.Person = DS.Model.extend({
firstName: DS.attr('string'),
birthday: DS.attr('date'),
day1: DS.attr('string'),
day2: DS.attr('string'),
day3: DS.attr('string')
});
For the purpose of this example, what if I had days go up to 50? Rather than going line by line... day4, day5, day6... is there a way to loop through dynamically? My first instinct is to use a MIXIN, and push these onto the object, but I don't think it would work if I had computed property:
isHoliday: function(){
if(this.get('day1') == 'off'){
return true;
}
}.property('day1'),
Given that 'this' is in there and we have a return, I don't believe you can simply 'push' this onto the model to generate something like this:
App.Person = DS.Model.extend({
firstName: DS.attr('string'),
birthday: DS.attr('date'),
day1: DS.attr('string'),
day2: DS.attr('string'),
day3: DS.attr('string'),
isHoliday: function(){
if(this.get('day1') == 'off'){
return true;
}
}.property('day1')
});
This is strange approach but still possible:
var defaults = {
firstName: DS.attr('string'),
birthday: DS.attr('date'),
isHoliday: function(){
if(this.get('day1') == 'off'){
return true;
}
}.property('day1')
}
var dayProps = {};
var count = 20;
while(count--){
dayProps['day' + (count + 1)] = DS.attr('string');
}
App.Person = DS.Model.extend(Ember.merge(defaults, dayProps));
instead defining with dynamic props, it is better to define Day model and have one-to-many relations with Person:
App.Person = DS.Model.extend({
days: DS.hasMany('day')
});
App.Day = DS.Model.extend({
person: DS.belongsTo('person')
});
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"},
}
]}
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.
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');
});
});