Definitive guide of when to use .get

Especially for nested variables I find I’m constantly just trying all the different combinations of stringing variables together with and without .get.

I’ve been messing with how to access my model instance from a view. For example say Im adding a variable to my controller…

startDate: parentView.controller.model.createdAt

…or is startDate: this.get(‘parentView’).get(‘controller’).get(‘model’).get(‘createdAt’)

…or maybe startDate: parentView.controller.get(‘model’).get(‘createdAt’)

or even… startDate: this.get(‘parentView.controller.model.createdAt’)

I feel like im always messing with adding and removing .get to attempt to get my variables working and I realise I really have no idea when to use which and when I must use .get and when I should not be using it.

My example is contrived from what I’ve been fiddling with recently and probably doesn’t represent good code, but I just wanted to show how the .get is causing me confusion and see if we can gather a clear guideline of when to use it and when not to.

4 Likes

I also struggle with this. Would be curious to hear more people’s thoughts on this.

@richiekhoo you might want check out some of the videos on

http://emberdumps.com

In particular checkout

POJOs vs Ember Objects, Ember.get

and

POJOs vs Ember Objects, Ember.set

2 Likes

Always use get(), and use it in one of the following two ways:

// If obj is guaranteed to not be null or undefined
obj.get('very.deep.nested.property');
// If obj might be null or undefined, or if it's not an Ember object,
Ember.get(obj, 'very.deep.nested.property');

Using get() is the only way to ensure that the Ember computed properties will always function properly. For instance, in your example, consider if model was a PromiseObject (which Ember-Data uses quite a bit):

// This will not work, since it won't activate the `unknownProperty` handler on `model`
var startDate = parentView.controller.model.createdAt;
// But this will work
var startDate = Ember.get(parentView, 'controller.model.createdAt');
11 Likes

Thanks @gordon_kristan that definitely helps.

I’ve been primarily using the quoted approach and yes I often get an ‘object is undefined’ style error. So your suggesting seems to be to do a get on the first object, comma separated by a get on the rest of the nested code. Did I understand the pattern correctly? Why does this work? And does this lead to less ‘object is undefined’ errors just by using this better/more correct syntax?

Curiously I’ve actually never seen Ember.get used explicitly in I think any of the examples I’ve seen elsewhere online (sure I could have easily missed stuff though).

In the context of using this code in a controller and wanting to get something from somewhere else, how does the ‘this’ variable play into your advice? In your example above labelled ‘But this will work’ you are just explicitly referring to ‘parentView’, do I not need to be using ‘this’ in my gets in this scenario?

Thanks @eccegordo I didn’t know of EmberDumps and will def check em out. Any tips you want to add yourself from your understanding of .get? Or even a little more details on what confuses you too.

I plan to report back with anything I learn as I delve into this as it feels like important “Ember Core Knowledge ™”

1 Like

Not sure I fully understand get. My understanding is that Ember extends the prototype for object to include the getters and setters. The main advantages is OOP. With stuff behind a getter you can encapsulate stuff and hide some of the implementation details “how it is gotten”. This is definitely probably the case with computed properties.

For more detail see the source here

another pattern I sometimes follow inside functions and computed properties is to break apart into varaibles. So for your example:

var parentView = this.get('parentView');
var controller = parentView.get('controller');
var model      = controller.get('model');
var createdAt  = model.get('createdAt');


if (model) {
  // do something with createdAt
}
2 Likes

The main advantage of Ember.get/set over obj.set/get is that it works with ember objects or POJO’s. So you don’t need to bother about the upcoming object. This is mainly used by addons, plugins and the framework itself. This PR is a good example of how changing this.foo to get(this, 'foo') gave more flexibility

1 Like

@gordan_kristan is right on. Always use get() and set() as opposed to accessing the properties directly. And yes, deeply nested properties should be accessed using obj.get('very.deeply.nested.property'). This way, your code adheres to the Uniform Access Principle. The code that reads the property does not need to worry about whether the property is computed, whether unknownProperty is being used in the chain, whether the property is being observed, or how ember-metal otherwise decides to handle the property. Ember’s philosophy is that these are internal details that should not be of concern to the object reading the property, so just use the get() / set() conventions at all times and you’ll be happy and productive.

Using obj.get('very.deeply.nested.property') will only throw an undefined error if obj is undefined. If any other property in the chain is undefined, then the call to get() will simply return undefined. If instead you called get() at every level, then it would throw an error if any level was undefined.

Another common pattern in Ember is to define an aliased property on the class that is consuming the property:

startDate: Ember.computed.alias('parentView.controller.model.createdAt')

This way, you can just call this.get('startDate') to read the value. This will keep your code DRY, and observers on startDate will work as well.

2 Likes