# Understanding Ember Objects, computed properties and observers - Ember.js Tutorial part 4

Paul Shan Sat Dec 10 2016

I’m using Ember 2.10.0 here

So we are in the part 4 of out Ember.js tutorial series. By now you would have already know how to install & scaffold ember and also about ember template syntaxes. In this part we will discuss about ember objects and why instead of POJO you need to use Ember.Object only.

Objects are very important in ember. Every element in ember is extended from Ember.Object; be it a controller, model, router or component. Ember also provides ways to write constructors and mixins like normal JavaScript objects.

## Class, Object, inheritance

While creating a class, you must inherit it from the base ember Object class, Ember.Object with the method .extend().

### How to define a class

const Student = Ember.Object.extend({
firstName: null,
lastName: null,
getFullName(){
return ${this.firstName}${this.lastName};
},
getStudentType(){
return "General Student";
}
});


As you can see, we’ve inherited the class Student from Ember.Object. So, the extend() method will be there in Student class as well. So let’s inherit another class PhDStudent from the class Student and try to override the methods.

const PhDStudent = Student.extend({
title: "Dr.",
getFullName(){
let studentFullName = this._super(); //same method of parent class can be called by ._super()
return ${this.title}${studentFullName};
},
getStudentType(){
return "PhD Student";
}
});


### Instance creation

An instance of any class can be created with the method .create(). Lets code some examples.

let jack = Student.create({
firstName: "Jack",
lastName: "Bauer"
});

let david = PhDStudent.create({
firstName: "David",
lastName: "Palmer"
});

jack.getFullName(); //Jack Bauer
david.getFullName(); //Dr. David Palmer

jack.getStudentType(); //General Student
david.getStudentType(); //PhD Student


### Setters and getters

As I said previously also, that you must obey the Ember way. You must do things the way ember wants you to do. Setters and getters are the perfect example for this.
While retrieving or setting a property of an object you need to use .get() an .set().

jack.get('firstName'); //Jack
jack.set('firstName', 'Jacky');
jack.get('firstName'); //Jacky


If you don’t use setters and getters and try to set or retrieve the value directly just as normal JavaScript object, the observers and computed properties will not work properly.

### Part wise class declaration - .reopen()

You don’t have to declare the entire class at one go. You can use the .reopen() to define the class partially. Below is an example.

const Student = Ember.Object.extend({
firstName: null,
lastName: null
});
Student.reopen({
school: "Void Canvas"
});
let stu = Student.create();
stu.get('school'); //Void Canvas


Likewise you can .reopen() the class multiple times and add/override the properties and methods.

### Static properties - .reopenClass()

Method .reopenClass() can be used to add/override static properties or methods to a class. The syntax is pretty similar to .reopen().

const Student = Ember.Object.extend({
});
Student.reopenClass({
website: "http://voidcanvas.com/"
});
let stu = Student.create();
stu.get('website'); //undefined
Student.website; // http://voidcanvas.com/


As you can see, using .reopenClass() we’ve introduced a static property named website. As this is a static one, so it can not be accessed by the instance stu. However you can get that from the class itself, which is Student. You can also declare static methods using .reopenClass().

### .reopen() vs .reopenClass()

The two methods .reopen() and .reopenClass() looks similar, but they do not do similar things.

• .reopen() is used to add/override properties and methods of any class.
• .reopenClass() is used to add/override static properties and methods.
• Properties added using .reopen() can not be accessed by the class name, however the ones added using .reopenClass() can only be accessed using the class.

An example below will clear the confusion.

const Student = Ember.Object.extend({
});
Student.reopenClass({
isActive: false
});
// override property of Student instance
Student.reopen({
isActive: true
});

Student.isActive; // false - because it is static property
let stu = Student.create();
stu.get('isActive'); // true


## Computed property

Computed properties are special kind of properties, which are dependent on other properties and calculate its value. Let me show you an example with our Student class.

const Student = Ember.Object.extend({
firstName: null,
lastName: null,
fullName: Ember.computed('firstName', 'lastName', function(){
return ${this.firstName}${this.lastName};
}),
init(){
this._super();
setTimeout(()=>{
this.set('firstName', 'David');
}, 5000);
}
});

let stu = Student.create({
firstName: "Paul",
lastName: "Shan"
});
stu.get('fullName');//Paul Shan
//after 5000 milliseconds
stu.get('fullName');//David Shan


As you can see, fullName is not a function here. It’s a property. You can .get() the property. Whenever the firstName or lastName property of the Student instance stu will change, the value of fullName will also change.

### watching array elements

The method above just observes a property of the ember object. But what if you want to observe each element of an array; or if someone inserted or deleted some elements from an array? Well, for that you can use @each. Below is an example.

const Student = Ember.Object.extend({
marks: null,
totalMarks: Ember.computed('marks.@each.score', function(){
let total = 0;
this.get('marks').forEach((mark)=>{
total+=mark.score;
});
}),
init(){
this._super();
this.set('marks', [
Ember.Object.create({subject: "Math", score: 60 }),
Ember.Object.create({subject: "Chemistry",  score: 70 }),
Ember.Object.create({subject: "Physics",  score: 80 })
]);

}
});

let stu = Student.create();
stu.get('totalMarks'); //210


### setters in computed properties

As computed properties are not normal properties where you can .set() a value; cause it’s a compute function; but there are ways to set the value. Here is an example.

const Student = Ember.Object.extend({
firstName: null,
lastName: null,
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;
}
})
});
let stu = Student.create({
firstName: "Paul",
lastName: "Shan"
});
stu.get('fullName');//Paul Shan
stu.set('fullName', 'David Palmer');
stu.get('fullName');//David Palmer


As you can see, here the last parameter of Ember.computed is not a function, but an object. This object has two methods get and set. The method get is just like the previous function in Ember.computed which just returns the aggregated value. However the set is a little tricky.
In set, it’s taking two parameters. First one is key which is the name of the computed property itself and the second one is value, which is the new value you want to set. So if we distribute the value properly to the properties on which our computed property is dependent upon, the problem will be solved. And that’s what we just did. We split the value and created two variables firstName and lastName and set them in the Ember Object’s firstName and lastName property.

### Macro in computed properties

There are so many common scenarios of computed properties in the world; considering whom, ember gave you some predefined macro. Below is one example of how a macro works, with the macro match which helps matching regx.

const Student = Ember.Object.extend({
email: null,
hasValidEmail: Ember.computed.match('email', /^.+@.+\..+\$/)
});

let stu = Student.create();
stu.get('hasValidEmail'); //false
stu.set('email','abcde');
stu.get('hasValidEmail'); //false
stu.set('email','paul@voidcanvas.com');
stu.get('hasValidEmail'); //true


The macros are really helpful and reduces the number of lines in your code. The list of the ember macros can be found in api documentation.

## Observers

As you already know about computed properties, it won’t be harder for you to understand observers. As the name suggests, the observers are there to observe the change of value in any property, including the computed properties.
The difference between computed property and observer is, you can not .get() an observer. It’s just a function to be executed whenever any of the property it’s observing changes. And computed property is a property and which will only recalculate if anywhere in your application that computed property is being .get().

const Student = Ember.Object.extend({
firstName: null,
lastName: null,
onFirstNameChange: Ember.observer('firstName', function(){
console.log("first name changed!");
}),
init(){
this._super();
setTimeout(()=>{
this.set('firstName', 'David');
}, 5000);
}
});

let stu = Student.create({
firstName: "Paul",
lastName: "Shan"
});
//after 5000 milliseconds the console will display
//first name changed!


Remember observer are heavy weighted elements; thus may cause performance issue if used excessively. Generally most of the problems can be solved using computed properties.

## Enumerable and Array

In ember an enumerable is an object which can contain multiple child objects in it. The most used enumerable is Array.
As ember means data binding and it needs to observe whenever a data is changed, it always forces you to go with the ember way. Usage of .set() and .get() are the example of it. Now, likewise in case of Array enumerable, you need to use .pushObject() and .popObject() instead of the default .push() and .pop(). There are alternative for other methods too.

Standard Method Ember Method
push pushObject
pop popObject
reverse reverseObjects
shift shiftObject
unshift unshiftObject

You can also get the first and the last object of an array with .get('firstObject') and .get('lastObject').

Few examples are as below.

let students = [
Student.create({
firstName: "Paul",
lastName: "Shan"
}),
Student.create({
firstName: "Jack",
lastName: "Bauer"
}),
Student.create({
firstName: "Sandip",
lastName: "Roy"
}),
Student.create({
firstName: "David",
lastName: "Palmer"
})
];
students.get('firstObject').get('firstName'); //Paul
students.get('lastObject').get('firstName'); //David
students.pushObject(Student.create({
firstName: "Rajinikanth"
}));
students.get('lastObject').get('firstName'); //Rajinikanth


You can check all Enumerable related apis in ember’s api documentation

## Next Part

Now you are well aware of ember objects and how they work. If you went through the api links we shared inside the article, you are probably aware of all syntaxes related to Objects. In the next part of this Ember.js full tutorial series, we will talk about Routers.

Ember TutorialEmber 2.10.0emberjs

Written By

## Paul Shan

• E

• R

• C

• S

### SEO

Search engine optimization

• E

• C

### CMS

wordpress, drupal, jumla, magento and more

Show All

### Tags

vue-js
Web development
vue css
social share buttons
real-life-example
react datetime picker
progra
Online
MathJax
jsfiddle
jquery chart library
instant search using vue
handlebars
event loop
Design
console.log
best practices
imorph

Show All