Computed properties

Objects in JavaScript are a combination of data (or properties), and behavior (or methods). It can also be thought as a key value store, wherein keys are the names of the properties and values containing the data or methods. You can access plain JavaScript properties by using either the dot notation or the bracket notation as follows:

var obj = { firstName: "suchit", lastName:"puri"};
console.log(obj.firstName); //Dot Notation
console.log(obj['lastName']); //Bracket Notation

Getter and setter methods

In order to provide features like property bindings, computed properties, auto updating templates, and a lot more, Ember.js framework uses get and set methods, instead of accessing the properties directly, as shown above. These methods, apart from returning and setting the properties on the object, also register property changes in the object, and will trigger any listeners that are observing this property:

var emberObject = Ember.Object.create({
  firstName:"suchit",
  lastName: "puri"
});
console.log(emberObject.get('firstName')); //suchit
emberObject.set('firstName',"something");
console.log(emberObject.get('firstName')); //something

The set method also lets you chain your setters. You could do something like the following:

emberObject.set('firstName',"something").set('lastName',"anything").get("firstName");

Such chaining of method calls can be really handy in seeding/changing data, while writing the test cases for Ember.Object instances.

Sometimes, instead of just using plain properties, you might want to transform or aggregate the data present in them. Computed properties in Ember.js let you use your functions as properties, so that you can add the logic to transform the data present in other properties. You can use get method to get the computed property, like any other property. Let's take a look at the following example:

import Ember from 'ember';

export default Ember.Object.extend({
  firstName: "",
  lastName: "",
  fullName: function(){
    return this.get('firstName') + " " + this.get('lastName'),
  }.property('firstName','lastName')
});

The contents of user.js are present in chapter-2/example5/app/user.js

Getting the user properties from app.js present in chapter-2/example5/app/app.js as follows:

import user from './user';

myUser = user.create({
  firstName: "suchit",
  lastName: "puri"
});
console.log(myUser.get('fullName')); //suchit puri

Here, as you can see, we have defined a user class. In this definition, we have defined a method fullName that returns the combination of your first name and last name. The only distinguishing factor about the fullName method is that we have explicitly made this function to act as a property, by appending the property at the end.

The property method makes a normal function act like an Ember.js object property. The arguments of the property method make the function dependent on other properties, which means that if any of the properties present in the arguments of the property method changes, the function recomputes its value.

Let's see that in the following example:

import Ember from 'ember';

export default Ember.Object.extend({
  firstName: "",
  lastName: "",
  fullName: function(){
    return this.get('firstName') + " " + this.get('lastName'),
  }.property('firstName','lastName')
});

The contents of user.js are present in chapter-2/example5/app/user.js

Getting/setting the user properties from app.js is present in chapter-2/example5/app/app.js, as follows:

import user from './user';

myUser = user.create({
  firstName: "suchit",
  lastName: "puri"
});

console.log(myUser.get('fullName')); //suchit puri
myUser.set("firstName","Tony");
myUser.set("lastName","Stark");
console.log(myUser.get('fullName'));//Tony Stark

If, after fetching in the full name, we decide to change the first name and last name of our user object, we can do this by using the set function on our object. The next time we go to fetch the fullName, we will get the updated fullName of the user.

Note

One important thing to note is that all the computed properties are cached by default, which means that once you request the computed property, the framework will compute it and cache it for you. The framework will only call the function again if any of the properties it is dependent on changes.

Let's take a look at the following example:

import Ember from 'ember';

export default Ember.Object.extend({
  firstName: "",
  lastName: "",
  fullName: function(){
    console.log("fullName computed property called");
    return this.get('firstName') + " " + this.get('lastName'),
  }.property('firstName','lastName')
});

The contents of user.js are present in chapter-2/example6/app/user.js

import user from './user';

var myUser = user.create({
  firstName: "suchit",
  lastName: "puri"
});

console.log(myUser.get('fullName'));
myUser.set("firstName","Tony");
myUser.set("lastName","Stark");
console.log(myUser.get('fullName'));
console.log(myUser.get('fullName'));

//Output

//"fullName computed property called"
//"suchit puri"
//"fullName computed property called"
//"Tony Stark"
//"Tony Stark"

The contents of app.js are present in chapter-2/example6/app/app.js

Let us have a look at the example:

  1. Here, we are first calling the fullName computed property on the user object, whose first name is suchit and last name is puri. Doing this, the function fullName is executed, which can be verified by seeing the console log statement "fullName computed property called". The full name of the user is printed as expected.
  2. Now let's change the firstName and lastName attributes of the user by using user.set, and get the new fullName of the user. Again, we can verify the console log statement getting printed, followed by the correct full name. Here, we see that since the first name and last name of the user were changed, the cache for the computed property was invalidated. When we called the full name computed property on the user object, the function was called again, and returned the correct full name of the user.
  3. Let us now call the fullName computed property again, without changing the firstName and lastName of the user. You can see in the output that the console log statement never gets printed. Since none of the dependent properties of fullName will change the framework, we will use the cached value of the computed property.

The key thing to understand here is that you need to include all the dependent properties correctly, while creating your computed property. Failing to do so will mean that the computed property will not return the correct results and will be using stale cached values.

Let's see that by an example, the chapter-2/example7/:

import Ember from 'ember';

export default Ember.Object.extend({
  firstName: "",
  lastName: "",
  fullName: function(){
    console.log("fullName computed property called");
    return this.get('firstName') + " " + this.get('lastName'),
  }.property('lastName')
});

The contents of user.js are present in chapter-2/example7/app/user.js

import user from './user';

var myUser = user.create({
  firstName: "suchit",
  lastName: "puri"
});

console.log(myUser.get('fullName'));
myUser.set("firstName","Tony");
console.log(myUser.get('fullName'));

//output
//"fullName computed property called"
//"suchit puri"
//"suchit puri"

The contents of app.js are present in chapter-2/example7/app/app.js

Here, we have removed the firstName dependency from our computed property fullName. Now fullName depends only on the lastName. Doing this, the cache of computed property would only get invalidated, if the last name changes.

Let us get the fullName of the user. We can see in the output that it returns the correct result. It calls in the function fullName, which returns the correct full name of the user. Now, if we update the firstName of the user, and call the fullName computed property on the user, it will still return the earlier cached value suchit puri, since none of the dependent property of the computed property has changed. You can see that such small things can result in unexpected behavior in your application. So, as a rule of thumb, include all the properties a computed property uses as dependent properties.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.224.54.168