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.
Related
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?
import Ember from 'ember';
export default Ember.Component.extend({
firstName: '',
lastName: '',
fullName: Ember.computed('firstName', 'lastName', {
get(key) {
return `${this.get('firstName')} ${this.get('lastName')}`;
},
set(key, value) {
let [firstName, lastName] = value.split(/\s+/);
this.set('firstName', firstName);
this.set('lastName', lastName);
return value;
}
})
});
Considering this example, why would one have a need for the key param?
The key returns the property name, fullName. It is generally not needed when you are defining a computed property. It is sometimes useful if you are writing a computed property macro. I usually leave it out.
Guide docs for computed with get/set: https://guides.emberjs.com/v2.17.0/object-model/computed-properties/#toc_setting-computed-properties
Here's an example usage from Ember source: deprecatingAlias
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.
I need to get hold of a value from another ember-data model in a computed property. All my belongsTo and hasMany relations are async : true.I have access to the value, however, it is displaying as '[Object, Object]' when I know the result actually resolves to the correct value from the debugger. I think it is due to my lack of understanding about promises.
displayName : function() {
return this.get('name') + ' ('+ this.get('currentGroup') + ')'; // currentGroup is displaying as '[Object, Object]' as it is pointing to the Promise I think
}.property('name'),
currentGroup : function() {
var promise = this.get('groups').then(function(groups) { //groups is async : true
//Do a bunch of complicated logic to work out a group based
//on the effective start date
return currentGroup.get('name'); // this resolves correctly in the debugger
});
return promise;
}.property()
currentGroup will return a promise a you wrote, so you should rather do it that way:
this.get('currentGroup').then(function(name) {
// note you have the name you returned in the promise's callback
})
so instead of having displayName property, you could have an observer:
displayName: null,
displayNameUpdate : function() {
this.get('currentGroup').then(function(name) {
var displayedName = this.get('name') + ' ('+ name + ')';
this.set('displayName', displayedName);
}.bind(this));
}.observes('name', 'currentGroup'),
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. :-(