Kevin Ball @kbal11
Loving The Nest
Understanding the Nesting Structure of the Ember.js
View Layer
Kevin Ball @kbal11
-Patrick J. Lynch and Sarah Horton, Web Style Guide 3.0
“Information hierarchies are the best way to
organize most complex bodies of
information”
http://webstyleguide.com/wsg3/3-information-architecture/3-site-structure.html
Kevin Ball @kbal11
Information Hierarchies On
the Web
• HTML is naturally nested
• Almost all content is naturally
nested
• Almost all applications are
naturally nested
Photo Credit: jamesjordan on Flickr, (cc)
Kevin Ball @kbal11
Kevin Ball @kbal11
Solved Problem?
What about SPAs?
Kevin Ball @kbal11
Framework Support
• Backbone - no core support.
• Marionette introduces concept of layouts. Nesting works, but
communication between levels is painful.
• Angular - no core support.
• Most popular approach is ui-router plugin - uses global state machine.
• Meteor.js - no core support
• Stackoverflow filled with questions and few answers
Kevin Ball @kbal11Image Source: https://imgflip.com/memegenerator/Frustrated-Boromir
Framework Support
Kevin Ball @kbal11
Faking Nesting
Diagram from http://guides.emberjs.com/v1.10.0/understanding-ember/the-view-layer/
Kevin Ball @kbal11
Framework Support
• React - YES
• Owner/ownee relationship
• Ember.js - YES
• Core Architecture of View Layer
Kevin Ball @kbal11
Supported Nesting
Diagram from http://guides.emberjs.com/v1.10.0/understanding-ember/the-view-layer/
Kevin Ball @kbal11Image Source: http://memecrunch.com/meme/12VFZ/yayyyy
Kevin Ball @kbal11
Ember.js Views
• Typically automatically created by a template
• Connected to a route and a controller
• Arranged hierarchically
• Events bubble naturally up the hierarchy
Kevin Ball @kbal11
Ember.js refresher
• Javascript MVC
• Very opinionated - strong conventions
• Emphasis on URLs representing state
Kevin Ball @kbal11
Ember View Layer
• Router — URLs and Hierarchy
• Route — Sets up for View
• Controller — Handles “View Logic” and semantic events
• View — Handles “interaction events”
• Template — Defines what gets rendered
Kevin Ball @kbal11
Ember View Layer
• Router — Always Needed!
• Route — Smart Defaults
• Controller — Smart Defaults
• View — Smart Defaults
• Template — Always Needed
Kevin Ball @kbal11
Router
$ cat app/router.js
!
import Ember from 'ember';
import config from './config/environment';
!
var Router = Ember.Router.extend({ location: config.locationType });
!
Router.map(function() {
this.resource('friends', function() {
this.route(‘new’);
!
this.route('show', {
path: ':friend_id'
});
!
this.route('edit', {
path: ':friend_id/edit'
});
});
});
Kevin Ball @kbal11
Templates
$ cat app/templates/friends.hbs
!
<h1>Friends Route</h1>
{{outlet}}
$ cat app/templates/friends/show.hbs
!
<div class="friend-profile">
<p>{{model.firstName}}</p>
<p>{{model.lastName}}</p>
<p>{{model.email}}</p>
<p>{{model.twitter}}</p>
<p>{{link-to 'Edit info' 'friends.edit' model}}</p>
<p><a href='#' {{action "delete" model}}>Delete</a></p>
</div>
Kevin Ball @kbal11
What Renders
<h1>Friends Route</h1>
{{outlet}}
<div class="friend-profile">
<p>{{model.firstName}}</p>
<p>{{model.lastName}}</p>
<p>{{model.email}}</p>
<p>{{model.twitter}}</p>
<p>{{link-to 'Edit info' 'friends.edit' model}}</p>
<p><a href='#' {{action "delete" model}}>Delete</a></p>
</div>
Router.map(function() {
this.resource('friends', function() {
this.route('show', {
path: ':friend_id'
});
});
});
GET /friends/1
Implicit route, controller, and view….
Kevin Ball @kbal11
<h1>Friends Route</h1>
<div class="friend-profile">
<p>{{model.firstName}}</p>
<p>{{model.lastName}}</p>
<p>{{model.email}}</p>
<p>{{model.twitter}}</p>
<p>{{link-to 'Edit info' 'friends.edit' model}}</p>
<p><a href='#' {{action "delete" model}}>Delete</a></p>
</div>
What Renders
Router.map(function() {
this.resource('friends', function() {
this.route('show', {
path: ':friend_id'
});
});
});
GET /friends/1
Implicit route, controller, and view….
Kevin Ball @kbal11
Routes
$ cat app/routes/friends/new.js
!
import Ember from 'ember';
!
export default Ember.Route.extend({
model: function() {
return this.store.createRecord('friend');
}
});
!
$ cat app/routes/friends.js
!
import Ember from 'ember';
export default Ember.Route.extend({
});
Kevin Ball @kbal11
New Template
$ cat app/templates/friends/new.hbs
!
<h1>Adding New Friend</h1>
<form {{action "save" on="submit"}}>
<h2>{{errorMessage}}</h2>
<fieldset>
{{input value=model.firstName placeholder="First Name"}}<br>
{{input value=model.lastName placeholder="Last Name"}}<br>
{{input value=model.email placeholder="email"}}<br>
{{input value=model.twitter placeholder="twitter"}}<br>
<input type="submit" value="Save"/>
<button {{action "cancel"}}>Cancel</button>
</fieldset>
</form>
Kevin Ball @kbal11
Controllers
!
$ cat app/controllers/friends/new.js
!
export default Ember.Controller.extend({
isValid: Ember.computed(/*…*/),
actions: {
save: function() {
if (this.get('isValid')) {
this.get('model').save().then(function(friend) {
this.transitionToRoute('friends.show', friend);
}.bind(this));
} else {
this.set('errorMessage', 'You have to fill all the fields');
}
return false;
},
cancel: function() {
return true;
},
}
});
Kevin Ball @kbal11
All The Pieces
export default Ember.Controller.extend({
isValid: Ember.computed(/*…*/),
actions: {
save: function() {/*…*/ return false;},
cancel: function() {/*…*/ return true;},
}
});
<h1>Adding New Friend</h1>
<form {{action "save" on="submit"}}>
<h2>{{errorMessage}}</h2>
<fieldset>
{{input value=model.firstName placeholder="First Name"}}<br>
{{input value=model.lastName placeholder="Last Name"}}<br>
{{input value=model.email placeholder="email"}}<br>
{{input value=model.twitter placeholder="twitter"}}<br>
<input type="submit" value="Save"/>
<button {{action "cancel"}}>Cancel</button>
</fieldset>
</form>
export default Ember.Route.extend({
model: function() {
return this.store.createRecord('friend');
}
});
Kevin Ball @kbal11
Ember View Layer
View
Route
Controller
Template
Data Events
Kevin Ball @kbal11
Ember View Layer: Nesting
And Bubbling
View
Route
Controller
Template
View
Route
Controller
Template
Route
Kevin Ball @kbal11Image Source: http://www.quickmeme.com/meme/3r88fs
Kevin Ball @kbal11
What Does It All Mean?
• View representation that matches visual
organization (hierarchical)
• Place event handlers where they belong in the
hierarchy
• Easy updates of related views
Kevin Ball @kbal11

Understanding the Nesting Structure of the Ember.js View Layer

  • 1.
    Kevin Ball @kbal11 LovingThe Nest Understanding the Nesting Structure of the Ember.js View Layer
  • 2.
    Kevin Ball @kbal11 -PatrickJ. Lynch and Sarah Horton, Web Style Guide 3.0 “Information hierarchies are the best way to organize most complex bodies of information” http://webstyleguide.com/wsg3/3-information-architecture/3-site-structure.html
  • 3.
    Kevin Ball @kbal11 InformationHierarchies On the Web • HTML is naturally nested • Almost all content is naturally nested • Almost all applications are naturally nested Photo Credit: jamesjordan on Flickr, (cc)
  • 4.
  • 5.
    Kevin Ball @kbal11 SolvedProblem? What about SPAs?
  • 6.
    Kevin Ball @kbal11 FrameworkSupport • Backbone - no core support. • Marionette introduces concept of layouts. Nesting works, but communication between levels is painful. • Angular - no core support. • Most popular approach is ui-router plugin - uses global state machine. • Meteor.js - no core support • Stackoverflow filled with questions and few answers
  • 7.
    Kevin Ball @kbal11ImageSource: https://imgflip.com/memegenerator/Frustrated-Boromir Framework Support
  • 8.
    Kevin Ball @kbal11 FakingNesting Diagram from http://guides.emberjs.com/v1.10.0/understanding-ember/the-view-layer/
  • 9.
    Kevin Ball @kbal11 FrameworkSupport • React - YES • Owner/ownee relationship • Ember.js - YES • Core Architecture of View Layer
  • 10.
    Kevin Ball @kbal11 SupportedNesting Diagram from http://guides.emberjs.com/v1.10.0/understanding-ember/the-view-layer/
  • 11.
    Kevin Ball @kbal11ImageSource: http://memecrunch.com/meme/12VFZ/yayyyy
  • 12.
    Kevin Ball @kbal11 Ember.jsViews • Typically automatically created by a template • Connected to a route and a controller • Arranged hierarchically • Events bubble naturally up the hierarchy
  • 13.
    Kevin Ball @kbal11 Ember.jsrefresher • Javascript MVC • Very opinionated - strong conventions • Emphasis on URLs representing state
  • 14.
    Kevin Ball @kbal11 EmberView Layer • Router — URLs and Hierarchy • Route — Sets up for View • Controller — Handles “View Logic” and semantic events • View — Handles “interaction events” • Template — Defines what gets rendered
  • 15.
    Kevin Ball @kbal11 EmberView Layer • Router — Always Needed! • Route — Smart Defaults • Controller — Smart Defaults • View — Smart Defaults • Template — Always Needed
  • 16.
    Kevin Ball @kbal11 Router $cat app/router.js ! import Ember from 'ember'; import config from './config/environment'; ! var Router = Ember.Router.extend({ location: config.locationType }); ! Router.map(function() { this.resource('friends', function() { this.route(‘new’); ! this.route('show', { path: ':friend_id' }); ! this.route('edit', { path: ':friend_id/edit' }); }); });
  • 17.
    Kevin Ball @kbal11 Templates $cat app/templates/friends.hbs ! <h1>Friends Route</h1> {{outlet}} $ cat app/templates/friends/show.hbs ! <div class="friend-profile"> <p>{{model.firstName}}</p> <p>{{model.lastName}}</p> <p>{{model.email}}</p> <p>{{model.twitter}}</p> <p>{{link-to 'Edit info' 'friends.edit' model}}</p> <p><a href='#' {{action "delete" model}}>Delete</a></p> </div>
  • 18.
    Kevin Ball @kbal11 WhatRenders <h1>Friends Route</h1> {{outlet}} <div class="friend-profile"> <p>{{model.firstName}}</p> <p>{{model.lastName}}</p> <p>{{model.email}}</p> <p>{{model.twitter}}</p> <p>{{link-to 'Edit info' 'friends.edit' model}}</p> <p><a href='#' {{action "delete" model}}>Delete</a></p> </div> Router.map(function() { this.resource('friends', function() { this.route('show', { path: ':friend_id' }); }); }); GET /friends/1 Implicit route, controller, and view….
  • 19.
    Kevin Ball @kbal11 <h1>FriendsRoute</h1> <div class="friend-profile"> <p>{{model.firstName}}</p> <p>{{model.lastName}}</p> <p>{{model.email}}</p> <p>{{model.twitter}}</p> <p>{{link-to 'Edit info' 'friends.edit' model}}</p> <p><a href='#' {{action "delete" model}}>Delete</a></p> </div> What Renders Router.map(function() { this.resource('friends', function() { this.route('show', { path: ':friend_id' }); }); }); GET /friends/1 Implicit route, controller, and view….
  • 20.
    Kevin Ball @kbal11 Routes $cat app/routes/friends/new.js ! import Ember from 'ember'; ! export default Ember.Route.extend({ model: function() { return this.store.createRecord('friend'); } }); ! $ cat app/routes/friends.js ! import Ember from 'ember'; export default Ember.Route.extend({ });
  • 21.
    Kevin Ball @kbal11 NewTemplate $ cat app/templates/friends/new.hbs ! <h1>Adding New Friend</h1> <form {{action "save" on="submit"}}> <h2>{{errorMessage}}</h2> <fieldset> {{input value=model.firstName placeholder="First Name"}}<br> {{input value=model.lastName placeholder="Last Name"}}<br> {{input value=model.email placeholder="email"}}<br> {{input value=model.twitter placeholder="twitter"}}<br> <input type="submit" value="Save"/> <button {{action "cancel"}}>Cancel</button> </fieldset> </form>
  • 22.
    Kevin Ball @kbal11 Controllers ! $cat app/controllers/friends/new.js ! export default Ember.Controller.extend({ isValid: Ember.computed(/*…*/), actions: { save: function() { if (this.get('isValid')) { this.get('model').save().then(function(friend) { this.transitionToRoute('friends.show', friend); }.bind(this)); } else { this.set('errorMessage', 'You have to fill all the fields'); } return false; }, cancel: function() { return true; }, } });
  • 23.
    Kevin Ball @kbal11 AllThe Pieces export default Ember.Controller.extend({ isValid: Ember.computed(/*…*/), actions: { save: function() {/*…*/ return false;}, cancel: function() {/*…*/ return true;}, } }); <h1>Adding New Friend</h1> <form {{action "save" on="submit"}}> <h2>{{errorMessage}}</h2> <fieldset> {{input value=model.firstName placeholder="First Name"}}<br> {{input value=model.lastName placeholder="Last Name"}}<br> {{input value=model.email placeholder="email"}}<br> {{input value=model.twitter placeholder="twitter"}}<br> <input type="submit" value="Save"/> <button {{action "cancel"}}>Cancel</button> </fieldset> </form> export default Ember.Route.extend({ model: function() { return this.store.createRecord('friend'); } });
  • 24.
    Kevin Ball @kbal11 EmberView Layer View Route Controller Template Data Events
  • 25.
    Kevin Ball @kbal11 EmberView Layer: Nesting And Bubbling View Route Controller Template View Route Controller Template Route
  • 26.
    Kevin Ball @kbal11ImageSource: http://www.quickmeme.com/meme/3r88fs
  • 27.
    Kevin Ball @kbal11 WhatDoes It All Mean? • View representation that matches visual organization (hierarchical) • Place event handlers where they belong in the hierarchy • Easy updates of related views
  • 28.