Ember.js: OK to avoid this.get('attr')? - ember.js

My Ember.js model, view, and controller classes are getting a bit verbose. Part of this comes from writing this.get('attr') instead of this.attr.
Is it OK to always just write this.attr, as long as the attribute is declared directly, not via a binding?
(I understand that setting is a different issue -- you always have to call this.set('attr', value) in order to update dependent attributes and templates.)

IIRC, you can do this for private properties that you know will not be observable.
The convention is to prefix your private properties with an underscore (eg _myProperty) which tells Ember not to bind it.
See the docs for .get(), or check the source code if you're so inclined.

If the property is being observed or bound, you DON'T want to do 'this.attr'. The get command is the nexus through which observers and bindings are triggered.

The previous answers to that question are outdated by recent version of Ember. Since 3.1, which was released in April 2018, native ES5 getters could be used for computed properties also. In Ember 3.1 this.get('attr') is the object uses unknownProperty, is an Ember Data PromiseProxyObject or if using with a path and some elements of it may not be an object. Please refer to release notes for details. You will get a helpful assertion in that cases.

Related

ember Error: Compile Error: is not a helper

I got the following error while developing our front-end with Ember.js:
ember Error: Compile Error: '...' is not a helper
What is the meaning of this error?
Reason
Ember throws this error if there is no component or helper with the given name is not found in your project or your dependent addons.
How to solve
You should check the name of the component or helper that you have written (possible errors are spelling errors or writing directory structure of the component incorrectly).
This twiddle shows example of this error message when the component my-component is called as {{my-component2 x=x}} instead of {{my-component x=x}} mistakenly.
This error can also happen in older (pre-Octane) versions of Ember if you have your component in all the right places, but your component doesn't have a dash in its name. As per the docs, components are required to have at least one dash in their names:
Components must have at least one dash in their name. So blog-post is an acceptable name, and so is audio-player-controls, but post is not. This prevents clashes with current or future HTML element names, aligns Ember components with the W3C Custom Elements spec, and ensures Ember detects the components automatically.
If you try to create a component without a dash in its name, Ember won't find it and will give you this error.
It appears this requirement has been lifted in more recent versions of Ember, where components start with a capital letter to distinguish them from native HTML elements.
From the documentation:
Helpers allow you to add additional functionality to your templates beyond what is included out-of-the-box in Ember. Helpers are most useful for transforming raw values from models and components into a format more appropriate for your users.
It looks like you are using a non-defined helper. So please look through (and maybe provide) some more of your log output. You are probably using an undefined helper in one (or multiple) of your .hbs-files.
component and file name must be the same. This solution worked for me.

What is the difference between set(this, 'agentName', 'John') and this.set('agentName', 'John') in Ember?

The same is true for 'get' methods too. Like get(this, 'agentName') and this.get('agentName') returns the same value.
In the official ember doc for get method, it shows that we are supposed to pass 2 values to get. Then how does this.get('agentName') work accurately?
this.get(...) is a shortcut for Ember.get(this,...). However it is only available on ember objects, so only Ember.get works in plain js objects.
Have a look at this.get(...) implementation.
The getter and setter in Ember has been upgraded to handle unknown property, computed property and observers. Not many people would use setUnknownProperty() hook or the unknownProperty() hook with get and set, but there are computed properties and observers throughout most people's code. More on computed properties and observers.
So, the basic difference between your set() and this.set() has to do with the context of your function. When you call just set(), it has to be defined in that scope or imported from somewhere to get things done. Howeve, with this.set() the scope here is this. Depending on where you are calling the function the scope changes. For instance if you are in a component, this refers to the component class itself. Similar would be the case with controllers, routes and other ember objects. If you have object of your own and it does not extend any of ember classes, then this would still work with how it does in any other JavaScript code. So it will fall back to default getter and setter in JavaScript.
As you may have realized by now, when you call get(this, 'foo'), you are calling JavaScript's getter function and pass it the current context with property to be searched for. And when you say this.get('foo') you are calling get() from Ember.Object class, which can handle things I mentioned above. And as #Lux mentioned this.get('foo') is simplified to call Ember.get(this, 'foo').
Hope this helps. I do encourage reading Ember guides and API docs. Curent ember-cli and ember-data version is #2.12.0

Detect whether new Ember Data records have been changed by the user

When a new record is created using Ember Data, then get("isDirty") returns true. But as yet, the user has made no changes to the record, and we can discard it without losing any of the user's work.
Is there any official, supported way to detect this situation, where a record has been created but no properties have been set?
(There's in incomplete answer to this question for a much older version of Ember Data, before it was substantially overhauled. The didSetProperty function still exists in current releases, but it's undocumented. Still, it might be a possible path to a solution if nothing official can be found.)
Internally, the changed properties are tracked by the _attributes property. You could do a check of
record.get('isNew') && Ember.keys(record._attributes).length === 0
to see that it has just been created and nothing has been changed on it.
Note that this is not meant to be part of the external API, but I'm not aware of any external API to accomplish this.

EmberJS - A way to log undefined bindings

Is there a way to get Ember to log a warning or error if you reference a property that doesn't exist? Currently if you misspell a the name of a property bound in your handlebar template there is no warning, it just doesn't show anything, and it can be hard to find which property is incorrect.
I have LOG_BINDINGS enabled, which helps somewhat, but there is a lot of unrelated stuff to sort through.
There isn't any sort of general built-in debugging that I have found, but there is a mechanism to add your own.
Ember.Object calls a method 'unknownProperty' any time a 'get' call returns undefined. You can add a console.warn to this method to log the property. The documentation describes it as a way to make custom abstract method type handling.
http://emberjs.com/api/classes/Ember.Observable.html#method_get
Ember.Object.reopen(
unknownProperty: (property) ->
unless property is 'App' or property is 'Ember'
console.warn "Unknown property #{property} in #{#toString()}"
)
Notice the filtering of the global namespaces 'App' and 'Ember' - all calls to global properties still go through this interface, but for what we care about they are red herrings.
Unfortunately, if you try to do this by reopening Ember.Object itself, you get a bunch of junk you don't care about, because apparently this happens all the time, especially in the EventManager classes. I have gotten around this by applying it to Ember.ArrayController, Ember.ObjectController, and a Model class that all of my models inherit from.
I now get a neat warning message on the console instead of a blank page every time I accidentally type "hight" into handlebars instead of "height"
In a production solution one would want to link this to some kind of "debug" option in the build, I assume.
One half solution might be to use the log handlebars helper to log the property before using it, unfortunately a non existent property causes the template to not display at all. This is a common problem with handlebars not displaying errors.
{{log myProperty}}

Ember.Controller doesn't exist?

I'm just getting started with Ember. I'm a little confused on some things, as the guides on the main site seem to indicate different ways of working.
In the main docs (http://emberjs.com/documentation/), it indicates that a controller should just extend an ordinary Ember object like this:
Ember.Object.extend();
Which works fine for me.
Then in the guide to using Routing (http://emberjs.com/guides/outlets/) it suggests that there is a Controller object type that you can extend:
Ember.Controller.extend();
This doesn't work for me, and if I simply try to console.log Ember.Controller, its undefined.
I'm using Ember version 0.9.8.1.
Should I worry about this, or should I just carry on with extending Objects as my controllers?
0.9.8.1 is aging, and unfortunately even the guides on the site are ahead of it -- use latest (at https://github.com/emberjs/ember.js/downloads) to keep up with the most current best practices.
Update: 1.0-pre is out (emberjs.com), so that is the best to use. The docs / guides have been brought up to date.
I think #pauldechov means the specific "latest" build which you can find here: https://github.com/emberjs/ember.js/downloads
But also keep in mind that the documentation and "latest" are not always in sync.