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 Slide

  2. cball_

    View Slide

  3. cball_

    View Slide

  4. How did we get here?
    cball_

    View Slide

  5. cball_
    Why are components
    a good thing?

    View Slide

  6. cball_
    They are reusable.

    View Slide

  7. cball_
    They are isolated.

    View Slide

  8. cball_
    They are easy to test.

    View Slide

  9. cball_
    They eventually will be
    supported natively.

    View Slide

  10. Controllers
    cball_

    View Slide

  11. cball_
    2 Responsibilities

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  17. cball_
    So when do controllers
    go away?

    View Slide

  18. cball_
    2 Major Blockers

    View Slide

  19. cball_
    1. Query Params

    View Slide

  20. cball_
    2. Routable Components

    View Slide

  21. Component
    Building Blocks
    cball_

    View Slide

  22. yield
    cball_

    View Slide

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

    {{yield}}

    View Slide

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

    {{yield some thing}}

    View Slide

  25. 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 Slide

  26. Parent / Child
    cball_

    View Slide

  27. 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 Slide

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

    View Slide

  29. Contextual
    Components
    cball_

    View Slide

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

    View Slide

  31. 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 Slide

  32. Closure Actions
    cball_

    View Slide

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

    View Slide

  34. 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 Slide

  35. cball_

    View Slide

  36. 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 Slide

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

    View Slide

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

    View Slide

  39. Dynamic Components
    cball_

    View Slide

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

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

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

    {{component userProfileComponent}}

    View Slide

  41. Helpers
    cball_

    View Slide

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

    View Slide

  43. How to Component
    cball_

    View Slide

  44. Enforce DDAA.
    cball_

    View Slide

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

    View Slide

  46. cball_
    2-way binding

    View Slide

  47. cball_
    Angle Bracket Components
    =
    Glimmer Components

    View Slide

  48. cball_
    One way data flow by default.

    View Slide

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

    View Slide

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

    View Slide

  51. Use closure actions.
    cball_

    View Slide

  52. Use the route-action
    helper.
    cball_

    View Slide

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

    View Slide

  54. cball_

    View Slide

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

    View Slide

  56. Use dynamic
    Components
    cball_

    View Slide

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

    View Slide

  58. Make top-level
    Components.
    cball_

    View Slide

  59. Use helpers.
    cball_

    View Slide

  60. 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 Slide

  61. cball_
    Thanks!

    View Slide