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

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.

Related

Ember model access to belongsTo property return null

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?

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.

Ember.js this.super() what is the purpose

Lot of times i see the function
init: function() {
return this._super();
},
What is the purpose of this function and when to use them?
Can someone explain to me practically use?
Calling this._super() in the init calls the init function of the superclass.
The documentation gives this example:
App.Person = Ember.Object.extend({
say: function(thing) {
var name = this.get('name');
alert(name + " says: " + thing);
}
});
App.Soldier = App.Person.extend({
say: function(thing) {
this._super(thing + ", sir!");
}
});
var yehuda = App.Soldier.create({
name: "Yehuda Katz"
});
yehuda.say("Yes"); // alerts "Yehuda Katz says: Yes, sir!"

EmberJS: Unable to get the length of an hasMany array two levels down

Im trying to create a computed property to get me the sum of the length of all pages.
But i cannot figure out how to access a child so i can get the childs of that child.
App.Document = DS.Model.extend({
name: DS.attr('string'),
spreads: DS.hasMany('App.Spread'),
pagesCount: function() {
// Here is where i go wrong, i can get the length of spreads, but not access a spread to get the page length.
var spreadsLength = this.get('spreads.length');
var firstSpread = this.get('spreads')[0];
return firstSpread.get('pages.length');
}.property('spreads')
});
App.Spread = DS.Model.extend({
document: DS.belongsTo('App.Document'),
pages: DS.hasMany('App.Page')
})
App.Page = DS.Model.extend({
spread: DS.belongsTo('App.Spread'),
page_name: DS.attr('string'),
page_items: DS.hasMany('DS.PageItem')
})
Here is an example of how you get access to the first object in the array of spreads:
App.Document = DS.Model.extend({
name: DS.attr('string'),
spreads: DS.hasMany('App.Spread'),
pagesCount: function() {
// Here is where i go wrong, i can get the length of spreads, but not access a spread to get the page length.
var spreadsLength = this.get('spreads.length');
var firstSpread = this.get('spreads').objectAt(0);
// var firstSpread = this.get('spreads.firstObject'); // elegant way to first Object
return firstSpread.get('pages.length');
}.property('spreads.firstObject.pages.length')
});
But i guess you want to get the total number of pages here. So, here is an example how to iterate the spreads and sum the number of pages:
App.Document = DS.Model.extend({
name: DS.attr('string'),
spreads: DS.hasMany('App.Spread'),
pagesCount: function() {
// Here is where i go wrong, i can get the length of spreads, but not access a spread to get the page length.
var spreadsLength = this.get('spreads.length');
var ret = 0;
this.get("spreads").forEach(function(spread)){
ret += spread.get('pages.length');
}
return ret;
}.property('spreads.#each.pages.length')
});
Note: Look at the property dependency i declared via property. Since the ComputedProperty depend on those paths, you need to declare them there.
App.User = DS.Model.extend({
firstName: DS.attr('string'),
lastName: DS.attr('string'),
email: DS.attr('st App.User = DS.Model.extend({
firstName: DS.attr('string'),
lastName: DS.attr('string'),
email: DS.attr('string'),
phone: DS.attr('string'),
status: DS.attr('string', { defaultValue: 'new' }),
notes: DS.attr('string'),
// projects: DS.hasMany("project", {async: true}),
projectsCount: function() {
// alert(this.get('projects'));
return this.get('projects.length');
}.property('id'),
fullName: function() {
return this.get('firstName') + ' ' + this.get('lastName')
}.property('firstName', 'lastName')
}),
App.User.reopenClass({
valid: function(fields) {
return fields.firstName && fields.lastNameenter code here
}
});ring'),
phone: D App.User = DS.Model.extend({
firstName: DS.attr('string'),
lastName: DS.attr('string'),
email: DS.attr('string'),
phone: DS.attr('string'),
status: DS.attr('string', { defaultValue: 'new' }),
notes: DS.attr('string'),
// projects: DS.hasMany("project", {async: true}),
projectsCount: function() {
// alert(this.get('projects'));
return this.get('projects.length');
}.property('id'),
fullName: function() {
return this.get('firstName') + ' ' + this.get('lastName')
}.property('firstName', 'lastName')
}),
App.User.reopenClass({
valid: function(fields) { App.User = DS.Model.extend({
firstName: DS.attr('string'),
lastName: DS.attr('string'),
email: DS.attr('string'),
phone: DS.attr('string'),
status: DS.attr('string', { defaultValue: 'new' }),
notes: DS.attr('string'),
// projects: DS.hasMany("project", {async: true}),
projectsCount: function() {
// alert(this.get('projects'));
return this.get('projects.length');
}.property('id'),
fullName: function() {
return this.get('firstName') + ' ' + this.get('lastName')
}.property('firstName', 'lastName')
}),
App.User.reopenClass({
valid: function(fields) App.User = DS.Model.extend({
firstName: DS.attr('string'),
lastName: DS.attr('string'),
email: DS.attr('string'),
phone: DS.attr('string'),
status: DS.attr('string', { defaultValue: 'new' }),
notes: DS.attr('string'),
// projects: DS.hasMany("project", {async: true}),
projectsCount: function() {
// alert(this.get('projects'));
return this.get('projects.length');
}.property('id'),
fullName: function() {
return this.get('firstName') + ' ' + this.get('lastName')
}.property('firstName', 'lastName')
}),
App.User.reopenClass({
valid: function(fields) {
return fields.firstName && fields.lastNameenter code here
}
}); {
return fields.firstName && fields.lastNameenter code here
}
});
return fields.firstName && fields.lastNameenter code here
}
});S.attr('string'),
status: DS.attr('string', { defaultValue: 'new' }),
notes: DS.attr('string'),
// projects: DS.hasMany("project", {async: true}),
projectsCount: function() {
// alert(this.get('projects'));
return this.get('projects.length');
}.property('id'),
fullName: function() {
return this.get('firstName') + ' ' + this.get('lastName')
}.property('firstName', 'lastName')
}),
App.User.reopenClass({
valid: function(fields) {
return fields.firstName && fields.lastNameenter code here
}
});
App.User = DS.Model.extend({
firstName: DS.attr('string'),
lastName: DS.attr('string'),
email: DS.attr('string'), App.User = DS.Model.extend({
firstName: DS.attr('string'),
lastName: DS.attr('string'),
email: DS.attr('string'),
phone: DS.attr('string'),
status: DS.attr('string', { defaultValue: 'new' }),
notes: DS.attr('string'),
// projects: DS.hasMany("project", {async: true}),
projectsCount: function() {
// alert(this.get('projects'));
return this.get('projects.length');
}.property('id'),
fullName: function() {
return this.get('firstName') + ' ' + this.get('lastName')
}.property('firstName', 'lastName')
}),
App.User.reopenClass({
valid: function(fields) {
return fields.firstName && fields.lastNameenter code here
}
});
phone: DS.attr('string'),
status: DS.attr(' App.User = DS.Model.extend({
firstName: DS.attr('string'),
lastName: DS.attr('string'),
email: DS.attr('string'),
phone: DS.attr('string'),
status: DS.attr('string', { defaultValue: 'new' }),
notes: DS.attr('string'),
// projects: DS.hasMany("project", {async: true}),
projectsCount: function() {
// alert(this.get('projects'));
return this.get('projects.length');
}.property('id'),
fullName: function() {
return this.get('firstName') + ' ' + this.get('lastName')
}.property('firstName', 'lastName')
}),
App.User.reopenClass({
valid: function(fields) {
return fields.firstName && field App.User = DS.Model.extend({
firstName: DS.attr('string'),
lastName: DS.attr('string'),
email: DS.attr('string'),
phone: DS.attr('string'),
status: DS.attr('string', { defaultValue: 'new' }),
notes: DS.attr('string'),
// projects: DS.hasMany("project", {async: true}),
projectsCount: function() {
// alert(this.get('projects'));
return this.get('projects.length');
}.property('id'),
fullName: function() {
return this.get('firstName') + ' ' + this.get('lastName')
}.property('firstName', 'lastName')
}),
App.User.reopenClass({
valid: function(fields) {
return fields.firstName && fields.lastNameenter code here
}
});s.lastNameenter code here
}
});string', { defaultValue: 'new' }),
notes: DS.attr('string'),
// projects: DS.hasMany("project", {async: true}),
projectsCount: function() {
// alert(this.get('projects'));
return this.get('projects.length');
}.property('id'),
fullName: function() {
return this.get('firstName') + ' ' + this.get('lastName')
}.property('firstName', 'lastName')
}),
App.User.reopenClass({
valid: function(fields) {
return fields.firstName && fields.lastNameenter code here
}
});

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. :-(