React-style components with Ember.js

Struggles of a developer trying to write a goddam app

Pedro Chekos

  • I have a job
  • I love Ember
  • I hate triple IPAs

React-style?

  • Everything is a component
  • One way data-binding
  • Rich lifecycle hooks
    (componentWillMount, componentWillUpdate)
  • Data-down / Actions up
  • Flux: shared state in stores

Ember.js on Rotten Tomatoes

UX Before SPA

What it takes:

  • 1 application.hbs with {{outlet}}
  • 1 foo.hbs with {{outlet}}
  • N foo/bar.hbs

"This time we gonna create something unique, different, that challenges the laws of web design."

Any UX guy starting a new project.

Now the Sky's the limit

  • I am a list view that can turn into a multi-step creation flow
  • Each element in my list can be expanded
  • Once expanded feel free to edit any property or relationship
  • BTW I use liquid fire and I am fully responsive!

I have plenty of cool graphs to show and interact with!

I will stay here while the user plays with that insane top-container

If you are bored I am also a multi-step flow to enable some fairly useless feature or subscribe to our spamletter

Solution 1: The Ember Way

  1. Create a bunch of routes/controllers/templates
  2. Place named outlets all over the main template
  3. Use renderTemplate() to compose your view

{{outlet 'top'}}

{{outlet 'left'}}

{{outlet 'right'}}

export default Ember.Route.extend({
  renderTemplate() {
    this.render('posts/index', {
      into: 'main',
      outlet: 'top',
      controller: 'posts.index'
    });
    this.render('posts/graph', {
      into: 'main',
      outlet: 'left',
      controller: 'posts.graphs'
    });
    this.render('subscribe', {
      into: 'main',
      outlet: 'right',
      controller: 'subscribe'
    });
  }
});

New

Solution 2: The "React" Way

  1. Create a bunch of routes, 1 controller and 1 template
  2. Create at least 1 component for each "box"
  3. Compose your components based on current route

{{posts-graph ...}}

{{#if isListMode}}
    {{posts-list posts=posts}}
{{else}}
    {{posts-new post=newPost}}
{{/if}}

{{subscribe-flow}}

// posts controller
export default Ember.Controller.extend({

  mode: 'list',
  posts: [],
  newPost: null,

  isListMode: computed.equal('mode', 'list'),
  isCreateMode: computed.equal('mode', 'new')
});
// posts route
export default Ember.Route.extend({
  controllerName: 'posts',
  model() {
    return this.store.find('posts');
  },
  setupController(controller, model) {
    controller.set('mode', 'list');
    controller.set('hosts', model);
  }
});

// posts.new route
export default Ember.Route.extend({
  controllerName: 'posts',
  model() {
    return this.store.createRecord('post');
  },
  setupController(controller, model) {
    controller.set('mode', 'new');
    controller.set('newHost', model);
  }
});
// posts controller
export default Ember.Controller.extend({

  mode: 'list',
  posts: [],
  newPost: null,

  componentName: computed('mode', function() {
    return `posts-${this.get('mode')}`;
  })
});

{{component componentName posts=posts post=newPost}}

Since Ember 1.11

// posts controller
export default Ember.Controller.extend({
  actions: {
    savePost(post) {
      post.save().then( ()=> {
        this.transitionToRoute('posts');
      }
    }
  }
});
{{posts-new post=newPost submit='savePost'}}

Before Ember 1.13

// posts-new component
export default Ember.Component.extend({
  click() {
    this.sendAction(this.get('post'));
  }
});
// posts controller
export default Ember.Controller.extend({
  actions: {
    savePost(post) {
      post.save().then( ()=> {
        this.transitionToRoute('posts');
      }
    }
  }
});
{{posts-new post=newPost submit=(action 'savePost')}}

Since Ember 1.13

// posts-new component
export default Ember.Component.extend({
  click() {
    this.attrs.submit(this.get('post'));
  }
});

Thanks!

React-style components with Ember.js

By Guillaume Zurbach

React-style components with Ember.js

  • 957