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

Living in a Component World

Chris Ball
February 21, 2016

Living in a Component World

You have probably heard by now that Components are the way forward in Ember. Component all the things! Routeable Components haven't landed yet, and in the meantime you want to make sure you're building things the right way.

This talk will focus on using Components as the major building blocks in your application. We'll discuss Data Down/Actions Up, how to handle parent/child components, yielding, closure actions, and helpers using some test-driven examples to guide the way.

Chris Ball

February 21, 2016
Tweet

More Decks by Chris Ball

Other Decks in Programming

Transcript

  1. Living in a Component World
    cball_
    {{user-list}}
    {{profile-navigator}}
    {{gravatar-image}}
    {{signup-form}}
    {{comment-form as |form|}}
    {{#toggle-button}}
    hi
    {{else}}
    bye
    {{/toggle-button}} {{happy-user}}
    Component!

    View full-size slide

  2. How did we get here?
    cball_

    View full-size slide

  3. cball_
    Why are components
    a good thing?

    View full-size slide

  4. cball_
    They are reusable.

    View full-size slide

  5. cball_
    They are isolated.

    View full-size slide

  6. cball_
    They are easy to test.

    View full-size slide

  7. cball_
    They eventually will be
    supported natively.

    View full-size slide

  8. Controllers
    cball_

    View full-size slide

  9. cball_
    2 Responsibilities

    View full-size slide

  10. cball_
    2 Responsibilities
    1 - Decorate models for templates
    2 - Store state as a singleton

    View full-size slide

  11. cball_
    1 - Decorate models for templates
    Ember.Controller.extend({
    sort: ['ordinal:desc'],
    sortedThings: Ember.computed.sort('things', 'sort')
    });

    View full-size slide

  12. cball_
    2 Responsibilities
    1 - Decorate models for templates
    2 - Store state as a singleton

    View full-size slide

  13. cball_
    this.set('someProperty', true);
    .. change route ...
    when you come back its still true!
    2 - Store state as a singleton

    View full-size slide

  14. cball_
    1 - Decorate models for templates
    2 - Store state as a singleton
    Components
    Services

    View full-size slide

  15. cball_
    So when do controllers
    go away?

    View full-size slide

  16. cball_
    2 Major Blockers

    View full-size slide

  17. cball_
    1. Query Params

    View full-size slide

  18. cball_
    2. Routable Components

    View full-size slide

  19. Component
    Building Blocks
    cball_

    View full-size slide

  20. cball_
    {{#some-component}}
    This text gets inserted
    {{/some-component}}
    yield

    {{yield}}

    View full-size slide

  21. cball_
    {{#some-component as |some thing|}}
    {{concat some.name 'crazy'}}
    {{/some-component}}
    yield

    {{yield some thing}}

    View full-size slide

  22. cball_
    {{#car-list cars=cars as |car|}}
    Amazing {{car.name}}
    {{else}}
    Show when I have no cars.
    {{/car-list}}
    yield to inverse
    {{#each cars as |car|}}
    {{yield car}}
    {{/else}}
    {{yield to="inverse"}}
    {{/each}}

    View full-size slide

  23. Parent / Child
    cball_

    View full-size slide

  24. cball_
    {{!-- some-route/template.hbs --}}
    {{#custom-table as |table row|}}
    {{custom-column table=table name='foo'}}
    {{row.someProperty}}
    {{/custom-column}}
    {{/custom-table}}
    Parent/Child
    {{!-- custom-table/template.hbs --}}
    {{#each content as |row|
    {{yield this row}}
    {{/each}}

    View full-size slide

  25. cball_
    Parent/Child
    didInsertElement() {
    this.get('table').registerColumn(this);
    },
    willDestroyElement() {
    this.get('table').unregisterColumn(this);
    }

    View full-size slide

  26. Contextual
    Components
    cball_

    View full-size slide

  27. cball_
    Contextual Components
    New in Ember 2.3, pass a hash to yield that
    contains a component

    View full-size slide

  28. cball_
    Contextual Components
    {{!-- custom-table/template.hbs --}}
    {{#each content as |row|
    {{yield (hash row=(component 'crazy-row' table=this row=row)}}
    {{/each}}
    {{!-- some-route/template.hbs --}}
    {{#custom-table as |table|}}
    {{#table.row as |row|}}
    {{!-- something with row.someProperty --}}
    {{/table}}
    {{/custom-table}}

    View full-size slide

  29. Closure Actions
    cball_

    View full-size slide

  30. cball_
    Closure Actions
    Solution to send action to (or through)
    parent components.

    View full-size slide

  31. cball_
    Easy nested actions
    {{!-- some-route/template.hbs --}}
    {{my-component on-update-thing=(action 'doUpdate' thing)}}
    {{!-- parent-component/template.hbs --}}
    {{child-component on-update-thing=on-update-thing}}
    {{!-- child-component/template.hbs --}}
    Go!

    View full-size slide

  32. cball_
    They can also return values!
    {{!-- thing/template.hbs --}}
    {{my-component on-update-thing=(route-action 'doUpdate')}}
    {{!-- thing/route.js --}}
    export default Ember.Route.extend({
    actions: {
    doUpdate(thing) {
    return thing.save().then(() => doStuff());
    }
    }
    });

    View full-size slide

  33. cball_
    Basically, use closure
    actions all the time.

    View full-size slide

  34. cball_
    One use looks a bit strange.
    {{!-- my-component/template.hbs --}}

    View full-size slide

  35. Dynamic Components
    cball_

    View full-size slide

  36. cball_
    Dynamic Components
    {{!-- profile/template.hbs --}}

    {{component (concat userType '-profile')}}

    {{!-- profile/template.hbs --}}

    {{component userProfileComponent}}

    View full-size slide

  37. Helpers
    cball_

    View full-size slide

  38. cball_
    Helpers
    {{!-- some-route/template.hbs --}}
    {{my-chart options=(options-from-data data)
    {{!-- some-route/template.hbs --}}
    {{if (eq user currentUser)}}

    View full-size slide

  39. How to Component
    cball_

    View full-size slide

  40. Enforce DDAA.
    cball_

    View full-size slide

  41. cball_
    Data Down, Actions Up
    A way to reason about your
    app’s data flow.

    View full-size slide

  42. cball_
    2-way binding

    View full-size slide

  43. cball_
    Angle Bracket Components
    =
    Glimmer Components

    View full-size slide

  44. cball_
    One way data flow by default.

    View full-size slide

  45. cball_
    Prepare your apps for the
    future by enforcing DDAA!

    View full-size slide

  46. Don’t use attrs (yet).
    cball_

    View full-size slide

  47. Use closure actions.
    cball_

    View full-size slide

  48. Use the route-action
    helper.
    cball_

    View full-size slide

  49. cball_
    route-action helper
    Allows you to use closure
    actions that target the Route.

    View full-size slide

  50. cball_
    {{!-- foo/template.hbs --}}
    {{foo-bar clicked=(route-action "updateFoo" "Hello"
    "world")}}

    View full-size slide

  51. Use dynamic
    Components
    cball_

    View full-size slide

  52. Use pods (not required,
    but helpful).
    cball_

    View full-size slide

  53. Make top-level
    Components.
    cball_

    View full-size slide

  54. Use helpers.
    cball_

    View full-size slide

  55. cball_
    https://cdn.tutsplus.com/vector/uploads/legacy/qt/2011_QT/qt_26_wire_globe/preview.jpg
    Image Credits
    http://www.safetysign.com/images/catlog/product/large/X4526.png
    http://webcomponents.org/

    View full-size slide

  56. cball_
    Thanks!

    View full-size slide