new component patterns in ember.js

51
New Component Patterns in Ember 1.10+ or, You Really Can Take it With You

Upload: mixonic

Post on 16-Jul-2015

5.018 views

Category:

Technology


0 download

TRANSCRIPT

New Component Patterns in Ember 1.10+

or, You Really Can Take it With You

I’m Matthew@mixonic - madhatted.com

201 CreatedEmber.js experts and JavaScript superheroes in NYC

Out with the old,in with the new.

1 // app/index/controller.js 2 import Ember from "ember"; 3 4 export Ember.Controller.extend({ 5 session: Ember.inject.service(); 6 });

1 // app/services/session.js 2 import Ember from "ember"; 3 4 export Ember.Object.extend({ 5 isAuthenticated: false, 6 login: function() { 7 // ... 8 } 9 });

Services in 1.10!

HTMLBars dep! debug file!

1 <script src="/jquery.js"></script> 2 <script src="/handlebars-v2.0.0.js"></script> 3 <script src=“/1.9.1/ember.js”></script>

1 <script src="/jquery.js"></script> 2 <script src=“/1.10.0/ember-template-compiler.js”></script> 3 <script src=“/1.10.0/ember.debug.js”></script>

1.9

1.10

HTMLBars!

Love me!

New APIs mean new development patterns.

Out with the scopes,in with the variables.

I

Context switching deprecated in 1.9

1 {{! this context is the controller }} 2 {{#each model}} 3 {{name}} {{! this context is each person }} 4 {{/each}}

1 {{! this context is the controller }} 2 {{#each person in model}} 3 {{person.name}} {{! this context is still the controller }} 4 {{/each}}

http://emberjs.com/blog/2014/12/08/ember-1-9-0-released.html

Context switching deprecated in 1.9

http://emberjs.com/blog/2014/12/08/ember-1-9-0-released.html

1 {{#if config.pro}} 2 <div class="travis-lint"> 3 <p>Travis Lint for clean .yml files 4 <a {{bind-attr href="lintUrl"}}>lint.travis-ci.org/{{repo.slug}}</a> 5 </p> 6 </div> 7 {{/if}} 8 9 <table id="requests" class="list"> 10 <thead> 11 <tr> 12 <th>Request</th> 13 <th>Commit</th> 14 <th>Build</th> 15 <th>Commit message</th> 16 <th>Type</th> 17 <th>Message</th> 18 </tr> 19 </thead> 20 21 <tbody> 22 {{#each controller itemController="request"}} 23 <tr {{bind-attr class="requestClass"}}> 24 <td class="request-id"> 25 <span class="status"></span> 26 {{id}} 27 </td> 28 <td>{{githubCommitLink repo.slug commit.sha}}</td> 29 <td> 30 {{#if build}} 31 {{#link-to "build" build}}#{{build.number}}{{/link-to}} 32 {{else}} 33 - 34 {{/if}} 35 </td> 36 <td class="commit-message">{{{formatMessage commit.message short="true" repoBinding=build.repo}}}</td> 37 <td>{{type}}</td> 38 <td>{{message}}</td> 39 </tr> 40 {{/each}} 41 </tbody> 42 </table>

Context switching deprecated in 1.9

http://emberjs.com/blog/2014/12/08/ember-1-9-0-released.html

1 {{#if config.pro}} 2 <div class="travis-lint"> 3 <p>Travis Lint for clean .yml files 4 <a {{bind-attr href="lintUrl"}}>lint.travis-ci.org/{{repo.slug}}</a> 5 </p> 6 </div> 7 {{/if}} 8 9 <table id="requests" class="list"> 10 <thead> 11 <tr> 12 <th>Request</th> 13 <th>Commit</th> 14 <th>Build</th> 15 <th>Commit message</th> 16 <th>Type</th> 17 <th>Message</th> 18 </tr> 19 </thead> 20 21 <tbody> 22 {{#each controller itemController="request"}} 23 <tr {{bind-attr class="requestClass"}}> 24 <td class="request-id"> 25 <span class="status"></span> 26 {{id}} 27 </td> 28 <td>{{githubCommitLink repo.slug commit.sha}}</td> 29 <td> 30 {{#if build}} 31 {{#link-to "build" build}}#{{build.number}}{{/link-to}} 32 {{else}} 33 - 34 {{/if}} 35 </td> 36 <td class="commit-message">{{{formatMessage commit.message short="true" repoBinding=build.repo}}}</td> 37 <td>{{type}}</td> 38 <td>{{message}}</td> 39 </tr> 40 {{/each}} 41 </tbody> 42 </table>

New scope

1 <ul id="queues"> 2 <li class="queue"> 3 <h4>Queue ({{controller.length}})</h4> 4 <ul> 5 {{#if controller.length}} 6 {{#each job in controller}} 7 {{#view Travis.QueueItemView jobBinding="job"}} 8 {{#if job.repo.slug}} 9 {{#link-to "job" job.repo job}} 10 <span class="slug" {{bind-attr title="job.slug"}}> 11 {{job.repo.slug}} 12 </span> 13 #{{job.number}} 14 {{/link-to}} 15 {{/if}} 16 {{/view}} 17 {{/each}} 18 {{else}} 19 There are no jobs 20 {{/if}} 21 </ul> 22 </li> 23 </ul>

Context switching deprecated in 1.9

http://emberjs.com/blog/2014/12/08/ember-1-9-0-released.html

Possible new scope?!

Passing variables is easier to reason about than

changing scope.

Ember 1.10 introduces “block params”

1 {{! this context is the controller }} 2 {{#each person in model}} 3 {{person.name}} {{! this context is still the controller }} 4 {{/each}}

Block params introduced in 1.10

http://emberjs.com/blog/2014/12/08/ember-1-9-0-released.html

1 {{! this context is the controller }} 2 {{#each model as |person|}} 3 {{person.name}} {{! this context is still the controller }} 4 {{/each}}

http://emberjs.com/blog/2014/12/08/ember-1-9-0-released.html

1 {{#x-menu}} 2 {{x-item selected=selected item=item}} 3 {{/x-menu}}

Block params introduced in 1.10

1 <div class="x-menu"> 2 {{yield}} 3 </div>

http://emberjs.com/blog/2014/12/08/ember-1-9-0-released.html

1 {{#x-menu as |selected|}} 2 {{x-item selected=selected item=item}} 3 {{/x-menu}}

Block params introduced in 1.10

1 <div class="x-menu"> 2 {{yield selected}} 3 </div>

http://emberjs.com/blog/2014/12/08/ember-1-9-0-released.html

1 {{#x-menu as |selected item|}} 2 {{x-item selected=selected item=item}} 3 {{/x-menu}}

Block params introduced in 1.10

1 <div class="x-menu"> 2 {{yield selected item}} 3 </div>

1 <div class="x-menu"> 2 {{#each items as |item|}} 3 {{yield selected item}} 4 {{/each}} 5 </div>

http://emberjs.com/blog/2014/12/08/ember-1-9-0-released.html

1 {{#x-menu as |selected item|}} 2 {{x-item selected=selected item=item}} 3 {{/x-menu}}

Block params introduced in 1.10

Out with the controllers, in with the components.

II

Out with the views,in with the components.

II

Controllers Views

Receive actions Handle events

Provide template scope Describe elements

1 export default Ember.Component.extend({ 2 actions: { 3 save: function(model){ 4 model.save(); 5 } 6 } 7 });

1 <button {{action "save" model}}>Save</button>

Controllers Views

Receive actions Handle events

Provide template scope Describe elements

1 export default Ember.Component.extend({ 2 color: 'red' 3 });

1 <div>{{color}}</div>

Controllers Views

Receive actions Handle events

Provide template scope Describe elements

1 export default Ember.Component.extend({ 2 click: function(){ 3 this.sendAction('save'); 4 } 5 });

Controllers Views

Receive actions Handle events

Provide template scope Describe elements

1 export default Ember.Component.extend({ 2 tagName: 'li', 3 classNames: ['red'] 4 });

Controllers deprecated when 2.0 comes out

“Many people have noticed that controllers in Ember look a lot like

components, but with an arbitrary division of responsibilities. We agree!”

- Tomkatz, 2.0 RFC

https://github.com/emberjs/rfcs/pull/15

For new users, a single concept is easier to learn.

“But I need mega-hackz!”

III

I CAN HAZ

MEGAHACKZ

Components don’t yet handle every use-case

We’re working on it!

Here are some ideasNot finished, polished, or maybe even ever going to happen.

On Ember components that use the new tag syntax, data-binding will be one-way. The mut helper will wrap values that the receiver can

modify.

<x-input value={{mut name}}></x-input>

1 export default Ember.Component.extend({!2 tagName: 'input',!3 change: function(){!4 this.attrs.name.set(this.$().val());!5 }!6 });!

bind-action, or maybe action, will wrap the action it references in a closure, and pass it as

a function. You can call it directly.

{{x-input model=model submit=(bind-action "save")}}

1 export default Ember.Component.extend({ 2 change: function(){ 3 this.attrs.submit(model); 4 } 5 });

ref would allow you to point an action at a specific component in your current template.

1 {{video-player ref="vp"}} 2 3 <button on-click={{ref 'vp' 'play'}}>

set would allow you to easily map an event to a value setter.

<x-input on-change={{set model.name}}></x-input>

scoped helpers allow a component to yield references to components or helpers.

1 // app/components/form-for.js 2 3 import Ember from "ember"; 4 import FormForInput from "./helpers/input"; 5 6 var makeViewHelper = Ember.HTMLBars.makeViewHelper; 7 8 export default Ember.Component.extend({ 9 formHelpers: { 10 input: makeViewHelper(FormForInput) 11 } 12 });

1 {{! app/templates/components/form-for.hbs }} 2 3 {{yield formHelpers}}

1 {{! app/templates/post/new.hbs }} 2 3 {{#form-for as |f|}} 4 {{f.input label="Title" value=model.title}} 5 {{/form-for}}

Let’s cowboy code some prototypes

bit.ly/cowboy-codeBEWARE

An experiment with mut and bind-action

bit.ly/cowboy-1Using today’s tools

bit.ly/cowboy-2 block params

bit.ly/cowboy-3 bind-action

bit.ly/cowboy-4 more bind-action

bit.ly/cowboy-5 pass bind-action as block param

bit.ly/cowboy-6 yield with each

bit.ly/cowboy-7 mut

Start using block params today, and you will quickly want some of these tools.

Don’t let it stop you!

Thanks!Questions?