Use computed properties whenever applicable.
Use setProperties when you want to set multiple properties on an object with a single method call.
Do this:
this.setProperties({
'model.foo1': 'bar1',
'model.foo2': 'bar2',
'model.foo3': 'bar3'
});
Ember.setProperties(model, {
foo1: 'bar1',
foo2: 'bar2',
foo3: 'bar3'
});
Don't do this:
this.set('model.foo1', 'bar1');
this.set('model.foo2', 'bar2');
this.set('model.foo3', 'bar3');
model.set('foo1', 'bar1');
model.set('foo2', 'bar2');
model.set('foo3', 'bar3');
Always use Ember.computed.readOnly
when you don't need to set the property.
Use Ember.computed.oneWay
instead of Ember.computed.alias
unless there is a
specific reason for propagating changes back to the source. If you change this
property, it will diverge from the original one.
Use ES6 object destructuring for commonly used helpers, i.e.
const { computed, get, set, inject } = Ember;
Use .
as a separator for the Ember resolver. Use /
only for templates.
Do this for templates:
export default Ember.Component.extend({
layoutName: 'components/my-widget/widget',
});
Do this for the Ember resolver:
export default Ember.Controller.extend({
indexCtrl: Ember.inject.controller('main-widgets.index'),
});
Use camel case for action properties.
Do this:
{{my-component model=project onSave=(action "saveThings")}}
Don't do this:
{{my-component model=project onsave=(action "saveThings")}}
Use closure actions whenever applicable.
Prefer
<!-- template.hbs -->
{{my-component model=project onSave=(action "saveThings")}}
<!-- my-component.hbs -->
<button {{action attrs.onSave}}>Save</button>
Over
<!-- template.hbs -->
{{my-component model=project onSave="saveProject"}}
<!-- my-component.hbs -->
<button {{action "save"}}>Save</button>
// my-component.js
Ember.Component.extend({
actions: {
save: function() {
this.sendAction('onSave');
}
}
});
When using closure actions, access the passed closure using this.attrs
<!-- template.hbs -->
{{my-component model=project onSave=(action "doSomething")}}
<!-- my-component.hbs -->
<input type="text" oninput={{action "doIt" value="target.value"}} />
// my-component.js
Ember.Component.extend({
actions: {
doIt: function(value) {
this.attrs.onSave(value);
}
}
});
Use double quotes for HTML content, for Handlebars/HTMLBars syntax use simple quotes.
Do this:
<div class="foo">
{{my-component data-id='foo' (action 'saveFoo')}}
</div>
Don't do this:
<div class='foo'>
{{my-component data-id="foo" (action "saveFoo")}}
</div>
The order of declaration for a component is always properties, and then actions.
Use a single line when the parameter list is short.
Do this:
{{my-component foo=bar onSave=(action "saveFoo")}}
Don't do this:
{{my-component
foo=bar
onSave=(action "saveFoo")}}
Use "Clojure" style formatting when the parameter list is very long (>120 characters).
Do this:
{{my-component
title=name
details=accountName
resourceId=id
resourcePath="client/contacts"}}
Don't do this:
{{
my-component
title=name
details=accountName
resourceId=id
resourcePath="client/contacts"
}}
The highest level order is:
- Services;
- Native Properties; and
- Custom Properties.
Lifecycle hooks (e.g. model, setupController) should be in order of execution.
- Services;
- Native component properties;
- Passed / custom properties;
- Lifecycle hooks;
- Computed properties;
- Any native functions; and
- Actions.
Create a newline after each, and always line separate actions. So for example:
export default Ember.Component.extend({
tagName: 'li', // Native property
classNames: 'list-items', // Native property
title: 'Passed title', // Passed property
didInsertElement() { // Lifecycle hook
// code...
},
funnyTitle: computed('title', function() { // Computed property
const title = this.get('title');
return `FUNNY ${title}!`;
}),
actions: {
actionOne() {
// code...
},
actionTwo() {
// code...
}
}
});
- Service declarations;
- Lifecycle hooks;
- Any custom functions; and
- Actions.
- Service declarations;
- attrs;
- Relationships;
- Computed Properties; and
- Custom functions.
export default Model.extend({
title: attr('string'),
subTitle: attr('string'),
comments: hasMany('comment'),
author: belongsTo('user'),
someProperty: computed('title', function() {
// do something
});
});
NOTE: This chapter covers exclusively Ember ways of testing. There's a broad greater set of best practises on the particular Testing & QA section of the guide.
QUnit is the default testing framework for Ember and should be used along with ember-qunit Ember Addon that provides helpers for testing on this framework.
Tests files must be named as the file they belongs with the -test
ending word and must be placed on the path tests/{type}/{path}
, where type
is the test type (integration
, unit
) and path
is the path of the original file. For example:
File app/routes/main.js
should be unit tested on file tests/unit/routes/main-test.js
.
File app/pods/index/route.js
should be integrate tested on file tests/integration/pods/index/route-test.js
.
Acceptance tests must be named after the scenario they are trying to test. So, for example, a test on the login scenario can be located on tests/acceptance/login-test.js
.
Test helpers must be placed on tests/helpers
folder.
Learning Ember.js
Ember Addons
Testing Ember