I\'m new to Ember and it keeps confusing me about the difference between this.get()
and Ember.get()
. Can someone explain them briefly?
Welcome to Ember ;-)
Every object that extends Ember Observable mixin supports the get()
method (among others).
When you call this.get()
, the this
must refer to such an object (Route, Controller, Component, your own class that extends Ember.Object and so on). Calling get()
on plain object would cause a failure. Let me show the difference:
const emberObjectInstance = Ember.Object.create({
name: 'Bala'
});
emberObjectInstance.get('name'); // returns 'Bala'
const plainObject = { name: 'Bala'};
plainObject.get('name'); // causes a failure since get() is not a function
However, using Ember.get()
successes in both cases:
Ember.get(emberObjectInstance, 'name'); // returns 'Bala'
Ember.get(plainObject, 'name'); // returns 'Bala', too
which can be also written with imports as follows
import { get } from '@ember/object';
get(emberObjectInstance, 'name'); // returns 'Bala'
get(plainObject, 'name'); // returns 'Bala', too
Note: not to forget, calling either of get()
makes computed property get computed (in the most common cases, I don't want to dive deep now - lazy computation, volatile extensions etc), but for the sake of understanding the difference, we can work with plain values.
From own experience, I am using Ember.get()
everywhere I know a plain object might be the object whose property I need to retrieve. A nice example is setupController()
hook into which I may pass plain object from my unit tests to test setupController()
's functionality.
// some route:
setupController(controller, model){
this._super(...arguments);
const name = Ember.get(model, 'name'); // ***
controller.set('isNamePresentOnSetup', Ember.isPresent(name));
}
// in my unit tests I can use plain object:
...
const modelMock = { name: 'Bala' }; // plain object is enough because I use Ember.get instead of model.get() (see ***)?
const controllerMock = Ember.Object.create(); // has to be Ember.Object since I use controller.set() within setupController()
subject.setupController(controllerMock, modelMock);
assert.ok(controllerMock.get('isNamePresentOnSetup'), "property 'isNamePresentOnSetup' set up correctly if model name is present");
...
I could also user Ember.set(controller, 'isNamePresentOnSetup', Ember.isPresent(name))
and then pass plain controller mock into setupController()
, too.
I think this is a good start since you are new in Ember and I am sure Ember gurus would have much more to add. Relevant Ember docs:
https://guides.emberjs.com/v2.9.0/object-model/
https://guides.emberjs.com/v2.9.0/object-model/computed-properties/
https://guides.emberjs.com/v2.9.0/object-model/reopening-classes-and-instances/
UPDATE:
Using get()
with chained paths works different than working with POJOs.
For example in objectInstance.get('a.b.c')
if b
is undefined
the return value is undefined
. Converting this to objectInstance.a.b.c
when b is undefined
would instead raise an exception.
There is none. foo.get('bar')
is equivalent to Ember.get(foo, 'bar')
. However because foo.get
is defined on Ember.Object
you can only call .get()
on Ember Objects. Ember.get()
will work on all ember objects. On Ember Objects Ember.get(foo, 'bar')
is equivalent to foo.get('bar')
, on every other object its equivalent to foo['bar']
.
Please note that using Ember.get()
or this.get()
is not needed anymore for most use cases if running Ember >= 3.1, which was released in April 2018. You could now use native ES5 getters. A quick introduction to this change could be found in release notes for Ember 3.1. It's discussed more in detail in RFC 281.
There is a codemode available that helps you transition to ES5 getters: es5-getter-ember-codemod It could be run as part of ember-cli-update.
Please not that using Ember.get()
or this.get()
is not deprecated. It's still needed for some edge cases, that are listed in release notes linked above:
In fact there are several cases where you must still use get:
- If you are calling get with a chained path. For example in this.get('a.b.c') if b is undefined the return value is undefined. Converting this to this.a.b.c when b is undefined would instead raise an exception.
- If your object is using unknownProperty you must continue to use get. Using an ES5 getter on an object with unknownProperty will cause an assertion failure in development.
- Ember Data returns promise proxy objects when you read an async relationship and from other API. Ember proxy objects, including promise proxies, still require that you call get to read values.
Please note that there is a special case if using ember-changeset. It provides it's own .get()
implementation. Therefore Ember.get(this, 'value')
and this.get('value')
have different results if this
is an ember-changeset
. You find more information on that case in documentation of ember-changeset.