Ember computed properties transforms an object's function to a property. When you call the function that property will automatically get called. It's a great way to manipulate data.
Computed Properties Examples
Let's see some computed properties in action. For this post we'll be looking at some code from the official Ember guides.
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"
Let's break down this code. First we are creating a new Ember object with two properties, firstName and lastName. We have a function called 'fullName'. It returns back the first and last name. The '.property' simply sets the dependencies on the firstName and lastName.
The function will only be computed once, regardless of how many times it's called. The result is cached until either the fullName or lastName property changes. In that case it will be computed again next time it's called. Check out the jsbin below and test it out yourself.
Computed Property Methods
There is a handful or methods that you can use with computed properties. We'll go over a few basic ones.
If you really wanted to you could set a property as read only. In this case you will not be able to change the property. If you try to an exception will be thrown.
var Person = Ember.Object.extend({
guid: function() {
return 'guid-guid-guid';
}.property().readOnly()
});
var person = Person.create();
person.set('guid', 'new-guid'); // will throw an exception
Just like any other Ember object you can 'set' and 'get' properties within computed properties.
// get example
ironMan.get('fullName');
// set property
ironMan.set('firstName', 'John');
ironMan.set('lastName', 'Smith');
Let's say you didn't want the computed property to automatically cache its result. You can turn that feature off by using 'volatile'.
var outsideService = Ember.Object.extend({
value: function() {
return OutsideService.getValue();
}.property().volatile()
}).create();
Alternative Invocation
It's worth mentioning that Ember extends the function prototype. If you don't want to use '.property' you can use this alternative invocation.
fullName: Ember.computed('firstName', 'lastName', function() {
return this.get('firstName') + ' ' + this.get('lastName');
})
Here is an example below.
The computed method helper function accepts dependent keys and a function that accepts two parameters, key and value. You can pass in as many dependent keys as you like. This is the preferred way to define computed properties when writing third-party libraries.
Aggregate Data
The last thing we'll look at is aggregate data. Here is an example below.
App.TodosController = Ember.Controller.extend({
todos: [
Ember.Object.create({ isDone: true }),
Ember.Object.create({ isDone: false }),
Ember.Object.create({ isDone: true })
],
remaining: function() {
var todos = this.get('todos');
return todos.filterBy('isDone', false).get('length');
}.property('todos.@each.isDone')
});
Here we see a todos array with several Ember objects in them. We have a property 'remaining' that uses 'filterBy' which will return one item from the array that matches. So in this case it will return the number of Ember objects in the todo array that has 'isDone' set to false.
The '@each' is a special key that updates bindings and will fire the observer when certain events occur. You can see an example below.
Future
This is just a quick taste of Ember computed properties. We'll be looking into this more in the future. If you have any questions sign up for my email list and I'll try to answer them!