At Wicked Good Ember 2015, I discuss composability patterns in Ember.js and modern web development in general. Detailed case studies are examined in the areas of CSS, Computed Properties, Components and Testing
class="card blue-grey darken-1"> <div class="card-content white-text"> <div class="card-title"> Wicked Good Ember </div> This will go in the body of the card </div> <div class="card-action"> <a> <span {{action “accept”}}>Accept</span> </a> <a> <span {{action “cancel”}}>Cancel</span> </a> </div> </div>
common element <div class="card blue-grey darken-1"> <div class="card-content white-text"> <div class="card-title"> Wicked Good Ember </div> This will go in the body of the card </div> <div class="card-action"> <a> <span {{action “accept”}}>Accept</span> </a> <a> <span {{action “cancel”}}>Cancel</span> </a> </div> </div> {{#wge-card}} <div class="card-content white-text"> <div class="card-title"> Wicked Good Ember </div> This will go in the body of the card </div> <div class="card-action"> {{#wge-card-action}} <span {{action "accept"}}> Accept </span> {{/wge-card-action}} {{#wge-card-action}} <span {{action "cancel"}}> Cancel </span> {{/wge-card-action}} </div> {{/wge-card}}
common element <div class="card blue-grey darken-1"> <div class="card-content white-text"> <div class="card-title"> Wicked Good Ember </div> This will go in the body of the card </div> <div class="card-action"> <a> <span {{action “accept”}}>Accept</span> </a> <a> <span {{action “cancel”}}>Cancel</span> </a> </div> </div> {{#wge-card}} <div class="card-content white-text"> <div class="card-title"> Wicked Good Ember </div> This will go in the body of the card </div> <div class="card-action"> {{#wge-card-action}} <span {{action "accept"}}> Accept </span> {{/wge-card-action}} {{#wge-card-action}} <span {{action "cancel"}}> Cancel </span> {{/wge-card-action}} </div> {{/wge-card}} Not Useful
does everything <div class="card blue-grey darken-1"> <div class="card-content white-text"> <div class="card-title"> Wicked Good Ember </div> This will go in the body of the card </div> <div class="card-action"> <a> <span {{action “accept”}}>Accept</span> </a> <a> <span {{action “cancel”}}>Cancel</span> </a> </div> </div> {{#wge-card title="Wicked Good Ember" cardActions=myCardActions}} This will go in the body of the card {{/wge-card}}
does everything <div class="card blue-grey darken-1"> <div class="card-content white-text"> <div class="card-title"> Wicked Good Ember </div> This will go in the body of the card </div> <div class="card-action"> <a> <span {{action “accept”}}>Accept</span> </a> <a> <span {{action “cancel”}}>Cancel</span> </a> </div> </div> {{#wge-card title="Wicked Good Ember" cardActions=myCardActions}} This will go in the body of the card {{/wge-card}} Not Composable
title="Wicked Good Ember"}} This will go in the body of the card {{#wge-card-action}} <span {{action "accept"}}>Accept</span> {{/wge-card-action}} {{#wge-card-action}} <span {{action "cancel"}}>Cancel</span> {{/wge-card-action}} {{/wge-card}}
will go in the body of the card {{#wge-card-action}} <span {{action “accept"}}> Accept </span> {{/wge-card-action}} {{#wge-card-action}} <span {{action “cancel”}}> Cancel </span> {{/wge-card-action}} {{/wge-card}} Components Content projection - ruh roh <div class="card blue-grey darken-1"> <div class="card-content white-text"> <div class="card-title"> Wicked Good Ember </div> This will go in the body of the card </div> <div class="card-action"> <a> <span {{action “accept”}}>Accept</span> </a> <a> <span {{action “cancel”}}>Cancel</span> </a> </div> </div> 4 distinct pieces of content
will go in the body of the card {{#wge-card-action}} <span {{action “accept"}}> Accept </span> {{/wge-card-action}} {{#wge-card-action}} <span {{action “cancel”}}> Cancel </span> {{/wge-card-action}} {{/wge-card}} Components Content projection - ruh roh <div class="card blue-grey darken-1"> <div class="card-content white-text"> <div class="card-title"> Wicked Good Ember </div> This will go in the body of the card </div> <div class="card-action"> <a> <span {{action “accept”}}>Accept</span> </a> <a> <span {{action “cancel”}}>Cancel</span> </a> </div> </div> 4 distinct pieces of content Sub-components project into parent {{yield}} Simple property binding
title="Wicked Good Ember"}} This will go in the body of the card {{#wge-card-action}} <span {{action “accept"}}> Accept </span> {{/wge-card-action}} {{#wge-card-action}} <span {{action “cancel”}}> Cancel </span> {{/wge-card-action}} {{/wge-card}} • Child components won’t render directly • Parent will handle rendering of children • Register/unregister to parent
up at account's search list page”, function(assert) { server.get(`${apiHost.url}/me`, json(200, me)); server.get(`${apiHost.url}/campaigns/:id`, json(200, campaign1)); server.get(`${apiHost.url}/seats/2`, json(200, seat2)); server.get(`${apiHost.url}/seats/1`, json(200, seat1)); server.get(`${apiHost.url}/account/:id`, json(200, account1)); server.get(`${apiHost.url}/breadcrumbs`, json(200, breadcrumbs.campaign)); visit('/app/account/1/campaigns'); andThen(function() { assert.equal(currentPath(), ‘app.account.campaign', 'Current url is search list page for campaig assert.equal(Ember.$('.top-navbar .brand-logo .active-title').text().trim(), campaign1.campaign assert.equal(Ember.$('.resource-tiles-container .card').length, campaigns.campaigns.length, 'On assert.deepEqual(Ember.$('.resource-tiles-container .resource-tile:first-child .card .card-cont ['Created', 'Updated'], 'Columns are correct'); assert.equal(Ember.$('.new-campaign-button').length, 1, 'New Campaign button is on the screen') }); }); A lot of tests are verbose and ugly