Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Putting Composability to Work

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers. →

Putting Composability to Work

At the Ember NYC meetup

Avatar for Phil Gengler

Phil Gengler

February 26, 2016

Other Decks in Technology

Transcript

  1. Using composition in Ember - Mixins - Template helpers (like

    “action”, “mut”, “hash”, and “component”)
  2. Using composition in Ember - Mixins - Template helpers (like

    “action”, “mut”, “hash”, and “component”) - Addons providing composable elements: • ember-truth-helpers • ember-composable-helpers • ember-cpm • ember-composability • etc.
  3. Composition (not) in Ember In 2013 there was a PR

    to add composable computed properties to Ember Merged into master behind a feature flag in January 2014 Removed from master in March 2014 https://github.com/emberjs/ember.js/pull/3696
  4. Benefits of composition • Easier to reason about small bits

    of code • Easier to comprehensively test smaller and separate bits of code
  5. Benefits of composition • Easier to reason about small bits

    of code • Easier to comprehensively test smaller and separate bits of code • Less repetition since you can reuse bits of code you’ve already written
  6. Multiple behaviors for routes - using inheritance // app/routes/authenticated-route.js export

    default Ember.Route.extend({ /* auth-related stuff here * / }); // app/routes/confirms-when-leaving.js export default Ember.Route.extend({ /* install/uninstall event handler */ }); // app/routes/super-awesome.js export default Ember.Route.extend({ /* super awesome stuff in here */ }); // app/routes/authenticated-and-confirms-when-leaving.js export default Ember.Route.extend({ /* repeat your auth-related code here */ /* install/uninstall "onbeforeunload" handler */ }); // app/routes/authenticated-and-super-awesome.js export default Ember.Route.extend({ /* repeat your auth-related code in here again */ /* repeat your super awesome stuff in here */ }); // app/routes/confirms-when-leaving-and-super-awesome.js export default Ember.Route.extend({ /* install/uninstall "onbeforeunload" handler */ /* continue to repeat your super awesome stuff in here */ }); // app/routes/authenticate-and-confirms-and-super-awesome.js export default Ember.Route.extend({ /* repeat your auth-related code yet again */ /* install/uninstall "onbeforeunload" handler */ /* and repeat your super awesome stuff in here AGAIN */ });
  7. Multiple behaviors for routes - using mixins // app/routes/actual-route.js import

    AuthenticatedRouteMixin from '../mixins/authenticated-route'; import ConfirmsWhenLeavingMixin from '../mixins/confirms-when-leaving'; export default Ember.Route.extend( AuthenticatedRouteMixin, ConfirmsWhenLeavingMixin, { // your route here }); // app/mixins/authenticated-route.js export default Ember.Mixin.create({ /* auth-related stuff here * / }); // app/mixins/confirms-when-leaving.js export default Ember.Mixin.create({ /* install/uninstall event handler */ }); // app/mixins/super-awesome.js export default Ember.Mixin.create({ /* super awesome stuff in here */ });
  8. Using the `action` and `mut` helpers // app/components/attendance-counter.js export default

    Ember.Component.extend({ leftCounter: 0, rightCounter: 0 }); {{! app/templates/components/attendance-counter.hbs }} Left line: {{leftCounter}} {{incrementer-button value=leftCounter updateValue=(action (mut leftCounter))}} <br> Right line: {{rightCounter}} {{incrementer-button value=rightCounter updateValue=(action (mut rightCounter))}} // app/components/incrementer-button.js export default Ember.Component.extend({ actions: { clicked() { this.sendAction('updateValue', this.get('value') + 1); } } }); {{! app/templates/components/incrementer-button.hbs }} <button type='button' onclick={{action 'clicked'}}>+</button>
  9. Contextual components From the Ember 2.3 release announcement: {{! app/templates/components/alert-box.hbs

    }} <div class="alert-box"> {{yield (hash close-button=(component 'alert-box-button' onclick=(action 'close')) )}} </div>
  10. Mixing mixins Given this setup, what do you think will

    be logged? // app/mixins/thing-one.js export default Ember.Mixin.create({ value: 0, didInsertElement() { let value = this.get('value'); console.log('thing-one: %s', value); } }); // app/mixins/thing-two.js export default Ember.Mixin.create({ value: 'abc', didInsertElement() { let value = this.get('value'); console.log('thing-two: %s', value); } }); // app/components/log-stuff.js import ThingOne from '../mixins/thing-one'; import ThingTwo from '../mixins/thing-two'; export default Ember.Component.extend(ThingOne, ThingTwo);
  11. Which of these is easier to understand? {{#if (or user.isAdmin

    (eq page.owner user.id))}} {{#if userCanEditPage}} or