Skip to content

Latest commit

 

History

History
351 lines (243 loc) · 6.8 KB

File metadata and controls

351 lines (243 loc) · 6.8 KB

Emberjs Style Guide

alt text

Index

The Ember Way

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'),
});

Actions

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);
    }
  }
});

Templates

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"
}}

Order of Declaration

The highest level order is:

  1. Services;
  2. Native Properties; and
  3. Custom Properties.

Lifecycle hooks (e.g. model, setupController) should be in order of execution.

Components:

  1. Services;
  2. Native component properties;
  3. Passed / custom properties;
  4. Lifecycle hooks;
  5. Computed properties;
  6. Any native functions; and
  7. 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...
    }
  }
});

Routes:

  1. Service declarations;
  2. Lifecycle hooks;
  3. Any custom functions; and
  4. Actions.

Models:

  1. Service declarations;
  2. attrs;
  3. Relationships;
  4. Computed Properties; and
  5. Custom functions.
export default Model.extend({
  title: attr('string'),

  subTitle: attr('string'),

  comments: hasMany('comment'),

  author: belongsTo('user'),

  someProperty: computed('title', function() {
    // do something
  });
});

Testing

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.

Framework

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.

File organization

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.

Resources

Learning Ember.js

Ember Addons

Testing Ember