Ember.js at Molecule

why we switched and how it helped us

Adam Sunderland / @iterion

http://iterion.github.io/molecule-ember

Who we are

molecule logo
knockout logo

Issues/Limitations (for us)

  • Hard to split up into smaller pieces
  • Limited control of computed properties
  • No support for routing or urls
  • Server interaction is completely on us

Enter

ember logo

Components

  • Similar to Angular directives or Knockout bindingHandlers
  • Isolated
  • Reusable
  • Model complex user interactions

Example

Simple Note Component

Component


Molecule.NotesFieldComponent = Em.Component.extend
  actions:
    toggleNotes: ->
      @toggleProperty('showNotes')
            

Component Template


<div class="notes-label" {{action toggleNotes}}>
  {{yield}}
</div>
{{#if showNotes}}
<div class="notes-body">
  {{textarea value=notes}}
</div>
{{/if}}
            
notes-component

Using the component


{{#notes-field notes=trade.notes}}
  <i class="icon-file-text"></i>
  <span>Notes</span>
{{/notes-field}}
            
notes-component

Component


Molecule.NotesFieldComponent = Em.Component.extend
  actions:
    toggleNotes: ->
      @toggleProperty('showNotes')
            

Component Template


<div class="notes-label" {{action toggleNotes}}>
  {{yield}}
</div>
{{#if showNotes}}
<div class="notes-body">
  {{textarea value=notes}}
</div>
{{/if}}
            

Using the component


{{#notes-field notes=trade.notes}}
  <i class="icon-file-text"></i>
  <span>Notes</span>
{{/notes-field}}
            

Better code reuse throughout our app (we used the above in 3 different places and on two different models)

Computed Properties

This...


self.productName = ko.computed(function () {
  if (self.product()) {
    return self.product().name;
  }
});
            

Became:


productName: function () {
  return this.get('product.name');
}.property('product.name')
            

Or, even more concise:


productName: Ember.computed.alias 'product.name'
            

Knockout


<span data-bind="text: productName"><span>
            

Ember


{{productName}}
            

Ember Routing

Turns this:


            http://molecule.io/trades
            

into

  • loading of assets
  • rendering of ui

Routes are hierarchical

ApplicationRoute > TradesRoute > TradesIndexRoute

Usability win for SPA

Reduced asset loading

Ember Data

ember logo

wow

much conventions

so confuse

?

?

?

ActiveModelSerializer in Ruby

DS.ActiveModelSerializer in Ember-Data

It just works

Find all trades


@store.find('trade')
            

trade by id


@store.find('trade', 1)
            

arbitrary query


@store.find('trade', {product: "Ethane"})
            

promises


@store.find('trade', 1).then (trade) ->
  #called after ajax finishes and model is created
  trade.get('price')
            

updates


trade.set('price', 25);
trade.get('isDirty'); #true
trade.save();
            

Ember is omakase

convention over configuration

opinionated

Gotchas

Testing

It was hard, but now it's much easier with ember-testing

Third-Party Libraries

No Ember "gems"

Limited libraries/components to use

Sometimes hard to integrate with existing stuff (bootstrap in particular is a pain)

Good Resources

Thanks

Adam Sunderland / @iterion

doge language consultant: Hana Wang / @hahahanahaha

this presentation on github