Ember model access to belongsTo property return null - ember.js

I have a model Person with this property : address_fk: DS.belongsTo('address') refering to an Address model.
In the adress model, there are several properties such as zip_code , building ...
My goal is to create a computed property in Person to display the full address by accessing this.get('address_fk.zip_code') but it returns me undefined
I'm surely missing something here but I really don't know what.
Update : Problem solved, here is how :
adresse: computed('adresse_fk', function() {
return DS.PromiseObject.create({
promise: this.get('adresse_fk').then((adresse) => {
return adresse.get('escalier_etage_appartement') + ' ' + adresse.get('batiment') + ' ' + adresse.get('numero_nom_voie') + ' ' + adresse.get('code_postal') + ' ' + adresse.get('commune_fk.nom')
})
});
}),

you are defining the computed property on the Person model. The computed property may return a PromiseObject for the address. You could try these two things -
1 Check for the presence of adresse_fk
// Person model
adresse: Ember.computed('adresse_fk', function() {
if this.get('adresse_fk'){
return this.get('adresse_fk.escalier_etage_appartement') + ' '
+ this.get('adresse_fk.batiment') + ' ' +
this.get('adresse_fk.numero_nom_voie')
}
2 Use then to resolve promises
// Person model
adresse: Ember.computed('adresse_fk', function() {
this.get('adresse_fk').then( function(address){
return address.get('escalier_etage_appartement') + ' '
+ address.get('batiment') + ' ' +
address.get('numero_nom_voie')
}
}
I have not tested them but they should work.

//Address
export default DS.Model.extend({
point_de_consommation_fk: DS.hasMany('pointdeconsommation'),
code_postal: DS.attr('string'),
escalier_etage_appartement: DS.attr('string'),
batiment: DS.attr('string'),
numero_nom_voie: DS.attr('string'),
commune_fk: DS.belongsTo('commune'),
personne_set: DS.hasMany('personne')
})
// Person model
export default DS.Model.extend({
categorie_code: DS.attr('personne-categorie-code'),
email: DS.attr('string'),
adresse_fk: DS.belongsTo('address'),
telephone1: DS.attr('string'),
telephone2: DS.attr('string', {defaultValue: ''}),
adresse: computed('adresse_fk', function() {
return this.get('adresse_fk.escalier_etage_appartement') + ' '
+ this.get('adresse_fk.batiment') + ' ' +
this.get('adresse_fk.numero_nom_voie')
}),
})
I also forgot to tell that sometimes my undefined value is showing
up. Maybe I need to wait on my template before calling the property?

Related

footable, expanded Row ID

I am using footable in a project.
I try to retrieve the ID of an expanded row.
a.k.a I want to retrieve the attribute row ID whenever I expand a row.
I have tried several sugested solutions, but all I get is "undefined" as a result.
This did not work:
$('#CustOrderTab').bind('footable_row_expanded', function(e){
var id = $(e.ft.row).val();
console.log('Row: ' + id + ' | ' + JSON.stringify(id));
});
Neither did this:
$('#CustOrderTab').bind('footable_row_expanded', function(e){
var id = $(e).attrib('id');
console.log('Row: ' + id + ' | ' + JSON.stringify(id));
});
Neither did this:
$('#CustOrderTab').bind('footable_row_expanded', function(e){
var id = $(e.ft.row).attrib('id');
console.log('Row: ' + id + ' | ' + JSON.stringify(id));
});
Neither did this:
$('#CustOrderTab').bind('footable_row_expanded', function(e){
var id = $(e).attrib('id');
console.log('Row: ' + id + ' | ' + JSON.stringify(id));
});
Neither did this:
$('#CustOrderTab').bind('footable_row_expanded', function(e){
var id = $(this).attrib('id');
console.log('Row: ' + id + ' | ' + JSON.stringify(id));
});
#CustOrderTab is the table name.
Any ideas or suggestions is more than welcome.
So I ended up working around the footable and go for pure jquery.
$('#CustOrderTab').find('tr').click( function(){
console.log('Row click: ' + ($(this).index()+1));
});
In the end it's all I needed.

What is the difference between the function Ember.computed() and function().property()?

App.Person = Ember.Object.extend({
// these will be supplied by `create`
firstName: null,
lastName: null,
fullName: function() {
return this.get('firstName') + ' ' + this.get('lastName');
}.property('firstName', 'lastName'),
fullName:Ember.computed('firstName','lastName', function() {
return this.get('firstName') + ' ' + this.get('lastName');
}
});
What is the difference between the function Ember.computed() or function().property()?
Why there are two ways (functions) to declares the function to be a computed property?
What are the differences, benefits?
Ember.computed() is an (clean) alternative to function().property() in case you are disabling prototype extensions.

What does .property(...) does in Emberjs?

I have been going through Emberjs docs. I came across topic called computed property. I have gone through each and every words there and yet the arguments passed to .property() does not make any sense.
Taking the first example from the doc.
App.Person = Ember.Object.extend({
// these will be supplied by `create`
firstName: null,
lastName: null,
fullName: function() {
return this.get('firstName') + ' ' + this.get('lastName');
}.property('firstName', 'lastName')
});
var ironMan = App.Person.create({
firstName: "Tony",
lastName: "Stark"
});
ironMan.get('fullName'); // "Tony Stark"
According to the doc
Notice that the fullName function calls property. This declares the function to be a computed property, and the arguments tell Ember that it depends on the firstName and lastName attributes.
Just to check the significance of arguments passed to .property() I modified them.
fullName: function() {
return this.get('firstName') + ' ' + this.get('lastName');
}.property('Captain', 'America')
});
ironMan.get('fullName') returns Tony Stark.
So the final question is, what is the significance of arguments passed to the .property()?
.property() is a shorter version of Ember.computed(). Elaborating your example
fullName: function() {
return this.get('firstName') + ' ' + this.get('lastName');
}.property('firstName', 'lastName')
});
So basically if you don't putup .property() it will be a simple method returning full Name after concatenation. But it gets executed all the time whenever you call the method. But if you add .property() [basically a computed property], value gets cached and avoid multiple executions.
If there is a change in firstName or lastName, you might want to update the fullName value in cache. Thats why we pass arguments inside .property() as .property('firstName', 'lastName') . This is basically concept of observers. So basically in 2nd code you written, you might think its working properly but when there is change in firstName or lastName, fullName won't get changed coz it is observing variables named Captain, America rather firstName, lastName.

Using linkTo inside a helper

I'm trying to create a comma separated list of teacher first names of a class.
So firstly I created a computed property like:
App.Class = DS.Model.extend({
title: DS.attr('string'),
description: DS.attr('string'),
start_date: DS.attr('date'),
end_date: DS.attr('string'),
teachers: DS.hasMany('App.Teacher'),
department: DS.attr('string'),
teacher_list: Ember.computed(function() {
var teachers = this.get('teachers');
var teachers_list = '';
teachers.forEach(function (teacher) {
teachers_list += teacher.get('first_name');
if (teachers.indexOf(teacher) < teachers.get('length') - 1) teachers_list += ', ';
});
return teachers_list;
}).property('teachers.#each.first_name')
});
And in the template it looks something like this:
...
<td>{{class.teacher_list}}</td>
...
But then I got the idea to make the first_names links to the teachers own page and here I'm stuck.
I've tried the following code but without luck.
App.js
Ember.Handlebars.registerBoundHelper('teachers_list', function(teachers) {
var teachers_list = '';
teachers.forEach(function (teacher) {
teachers_list += "{{#linkTo 'teacher' " + teacher.id + "}}{{teacher.first_name}}{{/linkTo}}";
if (teachers.indexOf(teacher) < teachers.get('length') - 1) teachers_list += ', ';
});
return (teachers_list);
});
Template
...
<td>{{teachers_list class.teachers}}</td>
...
Output
{{#linkTo 'teacher' 0}}{{teacher.first_name}}{{/linkTo}}, {{#linkTo 'teacher' 1}}{{teacher.first_name}}{{/linkTo}}, {{#linkTo 'teacher' 2}}{{teacher.first_name}}{{/linkTo}}
Is there somehow I from inside the helper can create the correct link?
Cheers
Solution
Template:
<td id="teacher-list">{{#each teacher in course.teachers}}<span>{{#linkTo 'teacher' teacher}}{{teacher.first_name}}{{/linkTo}}</span>{{/each}}</td>
CSS:
#teacher-list span:not(:last-of-type)::after { content: ", "; }
I'd rather do this in the template with a simple {{#each teachers}}...{{/each}}. Or, if you insist on doing it with a Handlebars helper, here is how you can do it: http://www.thesoftwaresimpleton.com/blog/2013/04/07/handlebars-helper/
Calling the linkTo helper function can be tricky, so as a middle ground I suggest building a view:
App.TeachersListView = Ember.View.extend({
teachers: null,
template: Ember.Handlebars.compile(
'{{#each teacher in view.teachers}}' +
'{{#linkTo "teachers" teacher}}{{teacher.name}}{{/linkTo}}' +
'{{/each}}'
)
});
And then use it like this:
{{view App.TeachersListView teachersBinding="teachersList"}}
But you should NEVER do this in the model, as it does no belong there. Also, I'd avoid naming anything to class/Class, as it's a reserved word in almost all languages, and you might run into unexpected errors.
Is this an answer to your question, or you need further help with the linkTo helper?

emberjs - property fires twice

Why does the "fullName" function in this code execute twice?
Person = Ember.Object.extend({
// these will be supplied by `create`
firstName: null,
lastName: null,
fullName: function() {
console.log('Full name function...');
var firstName = this.get('firstName');
var lastName = this.get('lastName');
return firstName + ' ' + lastName;
}.property('firstName', 'lastName')
});
App.tom = Person.create({
firstName: "Tom",
lastName: "Dale"
});
App.UsersView = Ember.View.create({
templateName: 'users',
users: [App.tom]
});
Later in google-chrome console:
App.tom.set('firstName', 'John')
This outputs to log twice.
Seems like a bug, indeed (added a JSFiddle to illustrate: http://jsfiddle.net/MikeAski/GRvgt/)...
The view is rerendered, and the computed property not cached yet. :-(