Dynamic Properties on Model with EmberJS - ember.js

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')
});

Related

Ember howto use model field values in Controller

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

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.js nested property calculations returning undefined

I'm having an issue with two levels of calculated properties. I'm a bit new to ember so would appreciate some pointers.
The basic problem is that there are two levels of calculated properties - one at the order level and one at the item level. The order level is dependent on the calculation on the item.
After binding to the form - the item level calculation works great and the form is updated as I change the quantity. The order total however does not seem to calculate at all. Am I missing something in the property dependencies?
App.Order = DS.Model.extend({
items: DS.hasMany('item', { async: true } ),
payment_cash: DS.attr('number'),
payment_card: DS.attr('number'),
payment_credit: DS.attr('number'),
balance: DS.attr('number'),
total: function() {
return this.get('items').reduce(function(value,lineItem) {
value += lineItem.get('total');
});
}.property("items.#each.total"),
itemCount: function() {
return this.get('items').reduce(function(value,lineItem) {
value += lineItem.get('quantity');
});
}.property("items.#each.quantity"),
});
App.Item = DS.Model.extend({
order: DS.belongsTo('item'),
product: DS.belongsTo('product'),
quantity: DS.attr('number'),
adjustment: DS.attr('number'),
total: function() {
return this.get('product.price') * this.get('quantity')
}.property('product.price', 'quantity' )
});
App.Product = DS.Model.extend( {
name: DS.attr('string'),
description: DS.attr('string'),
price: DS.attr('number'),
imagePath: DS.attr('string')
});
The problem is that your reduce function is not returning anything. Try this:
total: function() {
return this.get('items').reduce( function(value, lineItem) {
return value += lineItem.get('total');
}, 0 );
}.property("items.#each.total"),
itemCount: function() {
return this.get('items').reduce( function(value, lineItem) {
return value += lineItem.get('quantity');
} , 0);
}.property("items.#each.quantity"),

Find record from belongsTo association in Ember.js

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);
}
});

Acces parent record from an embedded object

Is there a way to access to the parent object of an embedded model object ? For example :
App.Person = DS.Model.extend({
name : DS.attr('string'),
emails : DS.hasMany('App.Email', { embedded: true })
});
App.Email = DS.Model.extend({
label : DS.attr('string'),
email : DS.attr('string'),
setParentUpdated: function() {
if(this.get('isDirty') == true)
// this.get('parent').get('stateManager').goToState('updated');
// I would like to do something like this.get('parent')
// to access 'App.Person' instance object
}.observes('isDirty')
});
Why not simply setup a belongsTo relation?
App.Email = DS.Model.extend({
person: DS.belongsTo('App.Person')
//...
});
Then you will be able to use the person property of the email.