SlideShare a Scribd company logo
Hi. I’m Matthew.
I build spiffy apps for clients in NYC
Thursday, September 19, 13
@mixonic
httP://madhatted.com
matt.beale@madhatted.com
Thursday, September 19, 13
Let’s go single page
Thursday, September 19, 13
AMBITIOUS
Thursday, September 19, 13
COMPLEX
Thursday, September 19, 13
Start simple.
Thursday, September 19, 13
title
body
preview submit
preview
Thursday, September 19, 13
title
body
preview submit
preview
Thursday, September 19, 13
1 <div style="clear:both">
2 <div style="float:left">
3 {{input value=title}}
4 {{textarea value=body}}
5 </div>
6 <div style="float:left">
7 {{post-preview markdown=body}}
8 </div>
9 </div>
10
11 <div style="clear:both">
12 <button style="float:left" {{action "preview"}}>Preview</button>
13 <button style="float:left" {{action "submit"}}>Submit</button>
14 </div>
Thursday, September 19, 13
Great! HTML.
Thursday, September 19, 13
HTML dictates layout.
Thursday, September 19, 13
HTML dictate layout.
Templates
Thursday, September 19, 13
AND YOUR
ARCHITECTURE
Thursday, September 19, 13
1 <div style="clear:both">
2 <div style="float:left">
3 {{input value=title}}
4 {{textarea value=body}}
5 </div>
6 <div style="float:left">
7 {{post-preview markdown=body}}
8 </div>
9 </div>
10
11 <div style="clear:both">
12 <button style="float:left" {{action "preview"}}>Preview</button>
13 <button style="float:left" {{action "submit"}}>Submit</button>
14 </div>
ACTION DOESNT TALK TO COMPONENTS
Thursday, September 19, 13
1 <div style="clear:both">
2 <div style="float:left">
3 {{input value=title}}
4 {{textarea value=body}}
5 </div>
6 <div style="float:left">
7 {{post-preview markdown=body}}
8 </div>
9 </div>
10
11 <div style="clear:both">
12 <button style="float:left" {{action "preview"}}>Preview</button>
13 <button style="float:left" {{action "submit"}}>Submit</button>
14 </div>
CHASM OF DOM
Thursday, September 19, 13
1 <div style="clear:both">
2 <div style="float:left">
3 {{input value=title}}
4 {{textarea value=body}}
5 </div>
6 <div style="float:left">
7 {{post-preview markdown=body viewName="preview"}}
8 </div>
9 </div>
10
11 <div style="clear:both">
12 <button style="float:left" {{action "preview" target=view.preview}}>Preview</button>
13 <button style="float:left" {{action "submit"}}>Submit</button>
14 </div>
WORKAROUND 1
Thursday, September 19, 13
1 <div style="clear:both">
2 <div style="float:left">
3 {{input value=title}}
4 {{textarea value=body}}
5 </div>
6 <div style="float:left">
7 {{view App.PostPreview markdownBinding=body viewName="preview"}}
8 </div>
9 </div>
10
11 <div style="clear:both">
12 <button style="float:left" {{action "preview" target=view.preview}}>Preview</button>
13 <button style="float:left" {{action "submit"}}>Submit</button>
14 </div>
WORKAROUND 2
Thursday, September 19, 13
1 <div style="clear:both">
2 <div style="float:left">
3 {{input value=title}}
4 {{textarea value=body}}
5 </div>
6 <div style="float:left">
7 {{render "post_preview" body}}
8 </div>
9 </div>
10
11 <div style="clear:both">
12 <button style="float:left" {{action "preview"}}>Preview</button>
13 <button style="float:left" {{action "submit"}}>Submit</button>
14 </div>
1 App.ApplicationRoute = Ember.Route.extend({
2 actions: {
3 preview: function(){
4 var controller = this.controllerFor('post_preview');
5 controller.updatePreview();
6 }
7 }
8 });
WORKAROUND 3
Thursday, September 19, 13
WORKAROUND 4
1 App.ApplicationRoute = Ember.Route.extend({
2 renderTemplate: function(){
3 this._super.apply(this, arguments);
4 this.render('post_preview', {
5 into: 'application',
6 outlet: 'preview',
7 controller: 'post_preview'
8 });
9 },
10 actions: {
11 preview: function(){
12 var app = this.controllerFor('application');
13 var preview = this.controllerFor('post_preview');
14 preview.set('markdown', app.get('body'));
15 }
16 }
17 });
18
19 App.PostPreviewController = Ember.Controller.extend();
1 <div style="clear:both">
2 <div style="float:left">
3 {{input value=title}}
4 {{textarea value=body}}
5 </div>
6 <div style="float:left">
7 {{outlet "preview"}}
8 </div>
9 </div>
10
11 <div style="clear:both">
12 <button style="float:left" {{action "preview"}}>Preview</button>
13 <button style="float:left" {{action "submit"}}>Submit</button>
14 </div>
Thursday, September 19, 13
When we pick between these
options...
Thursday, September 19, 13
We make design decisions.
Thursday, September 19, 13
•Re-usability as ui component
•re-usability as action
•If an action fires
•Where the action is handled
•The internals of preview
Thursday, September 19, 13
ARCHITECTURE
Thursday, September 19, 13
Architecture in Ember apps is
dictated by routes and templates.
Thursday, September 19, 13
Routes and templates decide how actions
propagate the controller/route tree, scope access
to dependencies, and are most subject to
external constraints.
Thursday, September 19, 13
Routes and templates decide how actions
propagate the controller/route tree, scope access
to dependencies, and are most subject to
external constraints.
Thursday, September 19, 13
Routes and templates decide how actions
propagate the controller/route tree, scope access
to dependencies, and are most subject to
external constraints.
Thursday, September 19, 13
Routes and templates decide how actions
propagate the controller/route tree, scope access
to dependencies, and are most subject to
external constraints.
Thursday, September 19, 13
Routes and templates decide how actions
propagate the controller/route tree, scope access
to dependencies, and are most subject to
external constraints.
Thursday, September 19, 13
“Understanding actions in two easy steps”
Thursday, September 19, 13
#1: Bubbling
Thursday, September 19, 13
WARNING
THEse slides describe the behavior IN rc8 and beyond.
behavior before the changes in rc8 is very similar to
what is described here, but not identical.
Thursday, September 19, 13
ACTION BUBBLING
1 var Actionable = Ember.Object.extend(Ember.ActionHandler);
2
3 var firstTarget = Actionable.create();
4
5 firstTarget.send("Wie Geht's");
6
7 // Nothing!
Thursday, September 19, 13
ACTION BUBBLING
1 var Actionable = Ember.Object.extend(Ember.ActionHandler);
2
3 var firstTarget = Actionable.extend({
4 actions: {
5 "Wie Geht's": function(){
6 console.log("Danke gut");
7 }
8 }
9 }).create();
10
11 firstTarget.send("Wie Geht's");
12
13 // Danke gut
Thursday, September 19, 13
ACTION BUBBLING
1 var Actionable = Ember.Object.extend(Ember.ActionHandler);
2
3 var secondTarget = Actionable.extend({
4 actions: {
5 "Wie Geht's": function(){
6 console.log("Und dir?");
7 }
8 }
9 }).create();
10
11 var firstTarget = Actionable.extend({
12 target: secondTarget,
13 actions: {
14 "Wie Geht's": function(){
15 console.log("Danke gut");
16 }
17 }
18 }).create();
19
20 firstTarget.send("Wie Geht's");
21
22 // Danke gut
Thursday, September 19, 13
ACTION BUBBLING
1 var Actionable = Ember.Object.extend(Ember.ActionHandler);
2
3 var secondTarget = Actionable.extend({
4 actions: {
5 "Wie Geht's": function(){
6 console.log("Und dir?");
7 }
8 }
9 }).create();
10
11 var firstTarget = Actionable.extend({
12 target: secondTarget,
13 actions: {
14 "Wie Geht's": function(){
15 console.log("Danke gut");
16 return true;
17 }
18 }
19 }).create();
20
21 firstTarget.send("Wie Geht's");
22
23 // Danke gut
24 // Und dir?
RETUrn true to continue
bubbling the action
Thursday, September 19, 13
ACTION BUBBLING
1 var Actionable = Ember.Object.extend(Ember.ActionHandler);
2
3 var secondTarget = Actionable.extend({
4 actions: {
5 "Wie Geht's": function(){
6 console.log("Und dir?");
7 }
8 }
9 }).create();
10
11 var firstTarget = Actionable.extend({
12 target: secondTarget,
13 actions: {
14 "Wie Geht's": null, // Or just don't define actions
15 }
16 }).create();
17
18 firstTarget.send("Wie Geht's");
19
20 // Und dir?
Thursday, September 19, 13
Controllers, Routes, Views, and
Components handle actions.
Thursday, September 19, 13
Only Controllers and Routes have
targets for bubbling.
Thursday, September 19, 13
#1: ROUTES ARE stateS. Kind of.
Thursday, September 19, 13
ROUTES ARE STATES1 var moodManager = Ember.StateManager.create({
2 initialState: 'good',
3 good: Ember.State.create({
4 gut: function(){
5 console.log('Ja');
6 }
7 }),
8 bad: Ember.State.create({
9 gut: function(){
10 console.log('Nein');
11 }
12 }),
13 quiet: Ember.State.create()
14 });
15
16 moodManager.send('gut');
17 // Ja
18
19 moodManager.transitionTo('bad');
20 moodManager.send('gut');
21 // Nein
22
23 moodManager.transitionTo('quiet');
24 moodManager.send('gut');
25 // Uncaught Error: <Ember.StateManager:ember138> could not respond to event gut
in state quiet.
Thursday, September 19, 13
ROUTES ARE STATES1 App = Ember.Application.create();
2
3 App.Router.map(function(){
4 this.route('good');
5 this.route('bad');
6 this.route('quiet');
7 });
8
9 App.GoodRoute = Ember.Route.extend({
10 actions: { gut: function(){ console.log('Ja'); } }
11 });
12
13 App.BadRoute = Ember.Route.extend({
14 actions: { gut: function(){ console.log('Nein'); } }
15 });
16
17 App.QuietRoute = Ember.Route.extend();
1 {{! application.hbs }}
2 <a {{action "gut"}}>Gut?</a>
3 {{#link-to "good"}}Get happy{{/link-to}}
4 {{#link-to "bad"}}Get sour{{/link-to}}
5 {{#link-to "quiet"}}Get quiet{{/link-to}}
Thursday, September 19, 13
ROUTES ARE STATES1 App = Ember.Application.create();
2
3 App.Router.map(function(){
4 this.route('good');
5 this.route('bad');
6 this.route('quiet');
7 });
8
9 App.GoodRoute = Ember.Route.extend({
10 actions: { gut: function(){ console.log('Ja'); } }
11 });
12
13 App.BadRoute = Ember.Route.extend({
14 actions: { gut: function(){ console.log('Nein'); } }
15 });
16
17 App.QuietRoute = Ember.Route.extend();
1 {{! application.hbs }}
2 <a {{action "gut"}}>Gut?</a>
3 {{#link-to "good"}}Get happy{{/link-to}}
4 {{#link-to "bad"}}Get sour{{/link-to}}
5 {{#link-to "quiet"}}Get quiet{{/link-to}}
ACTIOns always hit the
leaf route, regardless
of where they fire from
Thursday, September 19, 13
ROUTES ARE STATES
1 App = Ember.Application.create();
2
3 App.Router.map(function(){
4 this.route('good');
5 this.route('bad');
6 this.route('quiet');
7 });
8
9 App.GoodRoute = Ember.Route.extend({
10 actions: { gut: function(){ console.log('Ja'); } }
11 });
12
13 App.GoodController = Ember.Controller.extend({
14 actions: { gut: function(){ console.log('ignored :-('); } }
15 });
1 {{! application.hbs }}
2 <a {{action "gut"}}>Gut?</a>
3 {{#link-to "good"}}Get happy{{/link-to}}
4 {{#link-to "bad"}}Get sour{{/link-to}}
5 {{#link-to "quiet"}}Get quiet{{/link-to}}
BUT the TEMPLATE DECIDES
WHICH CONTROLLERS SEE
THAT ACTION
Thursday, September 19, 13
ACTIONS ON CONTROLLERS
•couples template to controller
•should not force use of NEEDs
ACTIONS ON routes
•have access to all controllers
•handled from any template on a page
Thursday, September 19, 13
Choose where to put an action.
Thursday, September 19, 13
Routes and templates decide how actions
propagate the controller/route tree, scope access
to dependencies, and are most subject to
external constraints.
Thursday, September 19, 13
1 <div style="clear:both">
2 <div style="float:left">
3 {{input value=title}}
4 {{textarea value=body}}
5 </div>
6 <div style="float:left">
7 {{post-preview markdown=body viewName="preview"}}
8 </div>
9 </div>
10
11 <div style="clear:both">
12 <button style="float:left" {{action "preview" target=view.preview}}>Preview</button>
13 <button style="float:left" {{action "submit"}}>Submit</button>
14 </div>
setting viewName causes
a property named
“preview” to be added on
the parentview of that
view with it’s own
instance
that “preview” property
can be set as a target
Thursday, September 19, 13
•Components access nothing
•views access parentView, controller
•controllers access A target (the
route or a parent controller) AND
OTHER CONTROLLERS via needs
•routes access all controllers and
models
•CHEAT WITH REGISTER/INJECT
Thursday, September 19, 13
CHEAT WITH REGISTER/INJECT
1 App = Ember.Application.create();
2
3 App.inject('route', 'session', 'controller:session');
4
5 App.IndexRoute = Ember.Route.extend({
6 beforeModel: function(){
7 console.log( this.get('session.user.name') );
8 }
9 });
10
11 App.SessionController = Ember.Controller.extend({
12 user: { name: 'Bob' }
13 });
Thursday, September 19, 13
1 {{render "post"}}
2 {{render "post" post}}
3 {{component content=post}}
4 {{view App.PostView contentBinding="post"}}
5 {{template "post"}}
THIS
dictates part of your architecture
Thursday, September 19, 13
When confused about an app, look
to the templates and the routes first.
Thursday, September 19, 13
“Controllers have lots of features!”
AKA
BUT PLEASE DON’t MAKE THEM CLEVER
Thursday, September 19, 13
“I AM SO CLEVER THAT
SOMETIMES I DON’T
UNDERSTAND A SINGLE WORD
OF WHAT I AM SAYING”
Oscar Wilde
Thursday, September 19, 13
Clever Controller 1
1 App.BooksController = Ember.ArrayController.extend({
2 needs: ['library'],
3 content: Em.computed.alias('controllers.library.books')
4 });
Thursday, September 19, 13
Clever Controller 1
1 App.BooksController = Ember.ArrayController.extend({
2 needs: ['library'],
3 content: Em.computed.alias('controllers.library.books')
4 });
assumption about library controller
Assumed to only be attached to a route (no item controller)
assumes books belong to a single library
Thursday, September 19, 13
LESS Clever Controller 1
1 App.BooksRoute = Ember.Route.extend({
2 model: function(){
3 this.modelFor('library').get('books')
4 }
5 });
6
7 // The Ember controller provided by convention is sufficient.
Thursday, September 19, 13
1 <div>
2 <ul class="tabs">
3 <li {{action "openSignIn"}}>Sign In</li>
4 <li {{action "openSignUp"}}>Sign Up</li>
5 <li {{action "openForgotPassword"}}>Forgot Password</li>
6 </ul>
7 {{#if isSignInOpen}}{{template "sign_in"}}{{/if}}
8 {{#if isSignUpOpen}}{{template "sign_up"}}{{/if}}
9 {{#if isForgotPasswordOpen}}{{template "forgot_password"}}{{/if}}
10 </div>
Clever Controller 2
1 App.SessionController = Em.Controller.extend({
2 isSignInOpen: false,
3 isSignUpOpen: false,
4 isForgotPasswordOpen: false,
5
6 actions: {
7 closeOptions: function(){
8 this.setProperties({
9 isSignInOpen: false,
10 isSignUpOpen: false,
11 isForgotPasswordOpen: false
12 });
13 },
14 openSignIn: function(){ this.closeOptions(); this.set('isSignUpOpen', true); },
15 openSignUp: function(){ this.closeOptions(); this.set('isSignUpOpen', true); },
16 openForgotPassword: function(){ this.closeOptions(); this.set('isForgotPasswordOpen', true); }
17 }
18 });
Thursday, September 19, 13
1 <div>
2 <ul class="tabs">
3 <li {{action "openSignIn"}}>Sign In</li>
4 <li {{action "openSignUp"}}>Sign Up</li>
5 <li {{action "openForgotPassword"}}>Forgot Password</li>
6 </ul>
7 {{#if isSignInOpen}}{{template "sign_in"}}{{/if}}
8 {{#if isSignUpOpen}}{{template "sign_up"}}{{/if}}
9 {{#if isForgotPasswordOpen}}{{template "forgot_password"}}{{/if}}
10 </div>
Clever Controller 2
1 App.SessionController = Em.Controller.extend({
2 isSignInOpen: false,
3 isSignUpOpen: false,
4 isForgotPasswordOpen: false,
5
6 actions: {
7 closeOptions: function(){
8 this.setProperties({
9 isSignInOpen: false,
10 isSignUpOpen: false,
11 isForgotPasswordOpen: false
12 });
13 },
14 openSignIn: function(){ this.closeOptions(); this.set('isSignUpOpen', true); },
15 openSignUp: function(){ this.closeOptions(); this.set('isSignUpOpen', true); },
16 openForgotPassword: function(){ this.closeOptions(); this.set('isForgotPasswordOpen', true); }
17 }
18 });
NOT. VERY. DRY.
NEW PANELS MUST BE ADDED ON COnTROLLER
NEW PANELS MUST BE ADDED IN TEMPLATE
Thursday, September 19, 13
1 <div>
2 <ul class="tabs">
3 <li {{action "openSignIn"}}>Sign In</li>
4 <li {{action "openSignUp"}}>Sign Up</li>
5 <li {{action "openForgotPassword"}}>Forgot Password</li>
6 </ul>
7 {{#if isSignInOpen}}{{template "sign_in"}}{{/if}}
8 {{#if isSignUpOpen}}{{template "sign_up"}}{{/if}}
9 {{#if isForgotPasswordOpen}}{{template "forgot_password"}}{{/if}}
10 </div>
Clever Controller 2
1 App.SessionController = Em.Controller.extend({
2 isSignInOpen: false,
3 isSignUpOpen: false,
4 isForgotPasswordOpen: false,
5
6 actions: {
7 closeOptions: function(){
8 this.setProperties({
9 isSignInOpen: false,
10 isSignUpOpen: false,
11 isForgotPasswordOpen: false
12 });
13 },
14 openSignIn: function(){ this.closeOptions(); this.set('isSignUpOpen', true); },
15 openSignUp: function(){ this.closeOptions(); this.set('isSignUpOpen', true); },
16 openForgotPassword: function(){ this.closeOptions(); this.set('isForgotPasswordOpen', true); }
17 }
18 });
NAV & DISPLAYED PANEL TIGHTLY COUPLED
panels cannot be controlled from other scopes
Thursday, September 19, 13
LESS Clever Controller 2
1 <div>
2 <ul class="tabs">
3 <li {{bind-attr class="isSignInOpen:active"}}{{action "openPanel" "signIn"}}>Sign In</li>
4 <li {{bind-attr class="isSignUpOpen:active"}}{{action "openPanel" "signUp"}}>Sign Up</li>
5 <li {{bind-attr class="isForgotPasswordOpen:active"}}{{action "openPanel" "forgotPassword"}}>Forgot Passw
6 </ul>
7 {{outlet "panel"}}
8 </div>
1 App.SessionRoute = Ember.Router.extend({
2 setupController: function(){
3 this._super.apply(this, arguments);
4 Em.run.once(this, function(){
5 this.send('openPanel', 'signIn');
6 });
7 },
8 actions: {
9 openPanel: function(panel){
10 this.controller.set('openPanel', panel);
11 this.render('panels/'+panel, {
12 into: 'session',
13 outlet: 'panel'
14 });
15 }
16 }
17 });
18
19 App.SessionController = Ember.Controller.extend({
20 isSignInOpen: Em.computed.equal('openPanel', 'signIn'),
21 isSignUpOpen: Em.computed.equal('openPanel', 'signUp'),
22 isForgotPasswordOpen: Em.computed.equal('openPanel', 'forgotPassword')
23 });
Thursday, September 19, 13
1 {{#each controller}}
2 {{name}}
3 {{/each}}
Clever Controller 3
1 App = Ember.Application.create();
2
3 App.IndexRoute = Ember.Route.extend({
4 model: function(){
5 return Ember.A([
6 { name: 'Munster' },
7 { name: 'Alpine Lace' },
8 { name: 'Tome' }
9 ]);
10 }
11 });
Thursday, September 19, 13
1 {{#each controller}}
2 {{name}}
3 {{/each}}
Clever Controller 3
1 App = Ember.Application.create();
2
3 App.IndexRoute = Ember.Route.extend({
4 model: function(){
5 return Ember.A([
6 { name: 'Munster' },
7 { name: 'Alpine Lace' },
8 { name: 'Tome' }
9 ]);
10 }
11 });
APPle invasion! apple invasion! apple invasion!
Thursday, September 19, 13
1 {{#each controller}}
2 {{name}}
3 {{/each}}
Clever Controller 31 App = Ember.Application.create();
2
3 App.IndexRoute = Ember.Route.extend({
4 model: function(){
5 return Ember.A([
6 { name: 'Munster' },
7 { name: 'Alpine Lace' },
8 { name: 'Tome' }
9 ]);
10 }
11 });
12
13 App.IndexController = Ember.ArrayController.extend({
14 itemController: 'fruitInvasion'
15 });
16
17 App.FruitInvasionController = Ember.ObjectController.extend({
18 name: function(){
19 return 'Apple invasion!';
20 }.property()
21 });
APPle invasion! apple invasion! apple invasion!
Changes context in the
template from outside the
template.
Thursday, September 19, 13
1 {{#each controller itemController='fruitInvasion'}}
2 {{name}}
3 {{/each}}
LESS Clever Controller 3
1 App = Ember.Application.create();
2
3 App.IndexRoute = Ember.Route.extend({
4 model: function(){
5 return Ember.A([
6 { name: 'Munster' },
7 { name: 'Alpine Lace' },
8 { name: 'Tome' }
9 ]);
10 }
11 });
12
13 App.FruitInvasionController = Ember.ObjectController.extend({
14 name: function(){
15 return 'Apple invasion!';
16 }.property()
17 });
Thursday, September 19, 13
“TOO CLEVER IS DUMB”
Ogden Nash
Thursday, September 19, 13
TL;DR
Thursday, September 19, 13
Don’t work so hard in controllers.
Thursday, September 19, 13
Look to routes and templates for
your application architecture.
Thursday, September 19, 13
Thanks!
@mixonic
httP://madhatted.com
matt.beale@madhatted.com
Thursday, September 19, 13

More Related Content

What's hot

Workshop 14: AngularJS Parte III
Workshop 14: AngularJS Parte IIIWorkshop 14: AngularJS Parte III
Workshop 14: AngularJS Parte III
Visual Engineering
 
Testing Ember Apps: Managing Dependency
Testing Ember Apps: Managing DependencyTesting Ember Apps: Managing Dependency
Testing Ember Apps: Managing Dependency
Matthew Beale
 
Good karma: UX Patterns and Unit Testing in Angular with Karma
Good karma: UX Patterns and Unit Testing in Angular with KarmaGood karma: UX Patterns and Unit Testing in Angular with Karma
Good karma: UX Patterns and Unit Testing in Angular with Karma
ExoLeaders.com
 
Swift Delhi: Practical POP
Swift Delhi: Practical POPSwift Delhi: Practical POP
Swift Delhi: Practical POP
Natasha Murashev
 
Patterns Are Good For Managers
Patterns Are Good For ManagersPatterns Are Good For Managers
Patterns Are Good For Managers
AgileThought
 
Rails is not just Ruby
Rails is not just RubyRails is not just Ruby
Rails is not just Ruby
Marco Otte-Witte
 
Practical Protocol-Oriented-Programming
Practical Protocol-Oriented-ProgrammingPractical Protocol-Oriented-Programming
Practical Protocol-Oriented-Programming
Natasha Murashev
 
Integrating React.js with PHP projects
Integrating React.js with PHP projectsIntegrating React.js with PHP projects
Integrating React.js with PHP projects
Ignacio Martín
 
Excellent
ExcellentExcellent
Excellent
Marco Otte-Witte
 
New improvements for web developers - frontend.fi, Helsinki
New improvements for web developers - frontend.fi, HelsinkiNew improvements for web developers - frontend.fi, Helsinki
New improvements for web developers - frontend.fi, Helsinki
Robert Nyman
 
Ember - introduction
Ember - introductionEmber - introduction
Ember - introduction
Harikrishnan C
 
Workshop 23: ReactJS, React & Redux testing
Workshop 23: ReactJS, React & Redux testingWorkshop 23: ReactJS, React & Redux testing
Workshop 23: ReactJS, React & Redux testing
Visual Engineering
 
Backbone.js and friends
Backbone.js and friendsBackbone.js and friends
Backbone.js and friends
Good Robot
 
Reliable Javascript
Reliable Javascript Reliable Javascript
Reliable Javascript
Glenn Stovall
 
Workshop 19: ReactJS Introduction
Workshop 19: ReactJS IntroductionWorkshop 19: ReactJS Introduction
Workshop 19: ReactJS Introduction
Visual Engineering
 
A New Baseline for Front-End Devs
A New Baseline for Front-End DevsA New Baseline for Front-End Devs
A New Baseline for Front-End Devs
Rebecca Murphey
 
Chaining et composition de fonctions avec lodash / underscore
Chaining et composition de fonctions avec lodash / underscoreChaining et composition de fonctions avec lodash / underscore
Chaining et composition de fonctions avec lodash / underscore
Nicolas Carlo
 
06 jQuery #burningkeyboards
06 jQuery  #burningkeyboards06 jQuery  #burningkeyboards
06 jQuery #burningkeyboards
Denis Ristic
 
Loadrunner
LoadrunnerLoadrunner
Loadrunner
danwrong
 

What's hot (19)

Workshop 14: AngularJS Parte III
Workshop 14: AngularJS Parte IIIWorkshop 14: AngularJS Parte III
Workshop 14: AngularJS Parte III
 
Testing Ember Apps: Managing Dependency
Testing Ember Apps: Managing DependencyTesting Ember Apps: Managing Dependency
Testing Ember Apps: Managing Dependency
 
Good karma: UX Patterns and Unit Testing in Angular with Karma
Good karma: UX Patterns and Unit Testing in Angular with KarmaGood karma: UX Patterns and Unit Testing in Angular with Karma
Good karma: UX Patterns and Unit Testing in Angular with Karma
 
Swift Delhi: Practical POP
Swift Delhi: Practical POPSwift Delhi: Practical POP
Swift Delhi: Practical POP
 
Patterns Are Good For Managers
Patterns Are Good For ManagersPatterns Are Good For Managers
Patterns Are Good For Managers
 
Rails is not just Ruby
Rails is not just RubyRails is not just Ruby
Rails is not just Ruby
 
Practical Protocol-Oriented-Programming
Practical Protocol-Oriented-ProgrammingPractical Protocol-Oriented-Programming
Practical Protocol-Oriented-Programming
 
Integrating React.js with PHP projects
Integrating React.js with PHP projectsIntegrating React.js with PHP projects
Integrating React.js with PHP projects
 
Excellent
ExcellentExcellent
Excellent
 
New improvements for web developers - frontend.fi, Helsinki
New improvements for web developers - frontend.fi, HelsinkiNew improvements for web developers - frontend.fi, Helsinki
New improvements for web developers - frontend.fi, Helsinki
 
Ember - introduction
Ember - introductionEmber - introduction
Ember - introduction
 
Workshop 23: ReactJS, React & Redux testing
Workshop 23: ReactJS, React & Redux testingWorkshop 23: ReactJS, React & Redux testing
Workshop 23: ReactJS, React & Redux testing
 
Backbone.js and friends
Backbone.js and friendsBackbone.js and friends
Backbone.js and friends
 
Reliable Javascript
Reliable Javascript Reliable Javascript
Reliable Javascript
 
Workshop 19: ReactJS Introduction
Workshop 19: ReactJS IntroductionWorkshop 19: ReactJS Introduction
Workshop 19: ReactJS Introduction
 
A New Baseline for Front-End Devs
A New Baseline for Front-End DevsA New Baseline for Front-End Devs
A New Baseline for Front-End Devs
 
Chaining et composition de fonctions avec lodash / underscore
Chaining et composition de fonctions avec lodash / underscoreChaining et composition de fonctions avec lodash / underscore
Chaining et composition de fonctions avec lodash / underscore
 
06 jQuery #burningkeyboards
06 jQuery  #burningkeyboards06 jQuery  #burningkeyboards
06 jQuery #burningkeyboards
 
Loadrunner
LoadrunnerLoadrunner
Loadrunner
 

Viewers also liked

Intro to emberjs
Intro to emberjsIntro to emberjs
Intro to emberjs
Mandy Pao
 
Developing Single Page Apps with Ember.js
Developing Single Page Apps with Ember.jsDeveloping Single Page Apps with Ember.js
Developing Single Page Apps with Ember.js
Leo Hernandez
 
Parse Apps with Ember.js
Parse Apps with Ember.jsParse Apps with Ember.js
Parse Apps with Ember.js
Matthew Beale
 
Avoiding Common Pitfalls in Ember.js
Avoiding Common Pitfalls in Ember.jsAvoiding Common Pitfalls in Ember.js
Avoiding Common Pitfalls in Ember.js
Alex Speller
 
Managing State in Single Page WebApps with Ember.js
Managing State in Single Page WebApps with Ember.jsManaging State in Single Page WebApps with Ember.js
Managing State in Single Page WebApps with Ember.js
Mark Mansour
 
The Immobile Web
The Immobile WebThe Immobile Web
The Immobile Web
Jason Grigsby
 
Architecture: ember.js and AngularJS
Architecture: ember.js and AngularJSArchitecture: ember.js and AngularJS
Architecture: ember.js and AngularJS
lrdesign
 
Integrating Ember.js into legacy applications
Integrating Ember.js into legacy applicationsIntegrating Ember.js into legacy applications
Integrating Ember.js into legacy applications
LevelbossMike
 
CSS Regression Tests with WebdriverCSS
CSS Regression Tests with WebdriverCSSCSS Regression Tests with WebdriverCSS
CSS Regression Tests with WebdriverCSS
Christian Bromann
 
20120518 mssql table_schema_xml_namespace
20120518 mssql table_schema_xml_namespace20120518 mssql table_schema_xml_namespace
20120518 mssql table_schema_xml_namespaceLearningTech
 
Delivering with ember.js
Delivering with ember.jsDelivering with ember.js
Delivering with ember.js
Andrei Sebastian Cîmpean
 
electron for emberists
electron for emberistselectron for emberists
electron for emberists
Aidan Nulman
 
Masa Israel Programs Overview
Masa Israel Programs OverviewMasa Israel Programs Overview
Masa Israel Programs Overview
Masa Israel Journey
 
Testing ember data transforms
Testing ember data transformsTesting ember data transforms
Testing ember data transforms
Sara Raasch
 
Ember Community 2016 - Be the Bark
Ember Community 2016 - Be the BarkEmber Community 2016 - Be the Bark
Ember Community 2016 - Be the Bark
Matthew Beale
 
Velocity spa faster_092116
Velocity spa faster_092116Velocity spa faster_092116
Velocity spa faster_092116
Manuel Alvarez
 
What I learned in my First 9 months of Ember
What I learned in my First 9 months of EmberWhat I learned in my First 9 months of Ember
What I learned in my First 9 months of Ember
Sara Raasch
 
LA Ember.js Meetup, Jan 2017
LA Ember.js Meetup, Jan 2017LA Ember.js Meetup, Jan 2017
LA Ember.js Meetup, Jan 2017
Matthew Beale
 
Nest v. Flat with EmberData
Nest v. Flat with EmberDataNest v. Flat with EmberData
Nest v. Flat with EmberData
Ryan M Harrison
 
Ember: Guts & Goals
Ember: Guts & GoalsEmber: Guts & Goals
Ember: Guts & Goals
Bob Lail
 

Viewers also liked (20)

Intro to emberjs
Intro to emberjsIntro to emberjs
Intro to emberjs
 
Developing Single Page Apps with Ember.js
Developing Single Page Apps with Ember.jsDeveloping Single Page Apps with Ember.js
Developing Single Page Apps with Ember.js
 
Parse Apps with Ember.js
Parse Apps with Ember.jsParse Apps with Ember.js
Parse Apps with Ember.js
 
Avoiding Common Pitfalls in Ember.js
Avoiding Common Pitfalls in Ember.jsAvoiding Common Pitfalls in Ember.js
Avoiding Common Pitfalls in Ember.js
 
Managing State in Single Page WebApps with Ember.js
Managing State in Single Page WebApps with Ember.jsManaging State in Single Page WebApps with Ember.js
Managing State in Single Page WebApps with Ember.js
 
The Immobile Web
The Immobile WebThe Immobile Web
The Immobile Web
 
Architecture: ember.js and AngularJS
Architecture: ember.js and AngularJSArchitecture: ember.js and AngularJS
Architecture: ember.js and AngularJS
 
Integrating Ember.js into legacy applications
Integrating Ember.js into legacy applicationsIntegrating Ember.js into legacy applications
Integrating Ember.js into legacy applications
 
CSS Regression Tests with WebdriverCSS
CSS Regression Tests with WebdriverCSSCSS Regression Tests with WebdriverCSS
CSS Regression Tests with WebdriverCSS
 
20120518 mssql table_schema_xml_namespace
20120518 mssql table_schema_xml_namespace20120518 mssql table_schema_xml_namespace
20120518 mssql table_schema_xml_namespace
 
Delivering with ember.js
Delivering with ember.jsDelivering with ember.js
Delivering with ember.js
 
electron for emberists
electron for emberistselectron for emberists
electron for emberists
 
Masa Israel Programs Overview
Masa Israel Programs OverviewMasa Israel Programs Overview
Masa Israel Programs Overview
 
Testing ember data transforms
Testing ember data transformsTesting ember data transforms
Testing ember data transforms
 
Ember Community 2016 - Be the Bark
Ember Community 2016 - Be the BarkEmber Community 2016 - Be the Bark
Ember Community 2016 - Be the Bark
 
Velocity spa faster_092116
Velocity spa faster_092116Velocity spa faster_092116
Velocity spa faster_092116
 
What I learned in my First 9 months of Ember
What I learned in my First 9 months of EmberWhat I learned in my First 9 months of Ember
What I learned in my First 9 months of Ember
 
LA Ember.js Meetup, Jan 2017
LA Ember.js Meetup, Jan 2017LA Ember.js Meetup, Jan 2017
LA Ember.js Meetup, Jan 2017
 
Nest v. Flat with EmberData
Nest v. Flat with EmberDataNest v. Flat with EmberData
Nest v. Flat with EmberData
 
Ember: Guts & Goals
Ember: Guts & GoalsEmber: Guts & Goals
Ember: Guts & Goals
 

Similar to Complex Architectures in Ember

Knockout.js presentation
Knockout.js presentationKnockout.js presentation
Knockout.js presentation
Scott Messinger
 
Backbone
BackboneBackbone
Backbone
Ynon Perek
 
Dependency management & Package management in JavaScript
Dependency management & Package management in JavaScriptDependency management & Package management in JavaScript
Dependency management & Package management in JavaScript
Sebastiano Armeli
 
Angular directive filter and routing
Angular directive filter and routingAngular directive filter and routing
Angular directive filter and routing
jagriti srivastava
 
Design Patterns for Tablets and Smartphones
Design Patterns for Tablets and SmartphonesDesign Patterns for Tablets and Smartphones
Design Patterns for Tablets and Smartphones
Michael Galpin
 
Desenvolvendo uma aplicação híbrida para Android e IOs utilizando Ionic, aces...
Desenvolvendo uma aplicação híbrida para Android e IOs utilizando Ionic, aces...Desenvolvendo uma aplicação híbrida para Android e IOs utilizando Ionic, aces...
Desenvolvendo uma aplicação híbrida para Android e IOs utilizando Ionic, aces...
Juliano Martins
 
Design for succcess with react and storybook.js
Design for succcess with react and storybook.jsDesign for succcess with react and storybook.js
Design for succcess with react and storybook.js
Chris Saylor
 
Android app development basics
Android app development basicsAndroid app development basics
Android app development basics
Anton Narusberg
 
Angular Workshop_Sarajevo2
Angular Workshop_Sarajevo2Angular Workshop_Sarajevo2
Angular Workshop_Sarajevo2
Christoffer Noring
 
Ngrx slides
Ngrx slidesNgrx slides
Ngrx slides
Christoffer Noring
 
Android 3
Android 3Android 3
Android 3
Robert Cooper
 
Google analytics
Google analyticsGoogle analytics
Google analytics
Lo Penny
 
Touch/Mobile Websites with jQuery Mobile - Boise Code Camp 2013
Touch/Mobile Websites with jQuery Mobile - Boise Code Camp 2013Touch/Mobile Websites with jQuery Mobile - Boise Code Camp 2013
Touch/Mobile Websites with jQuery Mobile - Boise Code Camp 2013
Brett Adler
 
MVI - Managing State The Kotlin Way
MVI - Managing State The Kotlin WayMVI - Managing State The Kotlin Way
MVI - Managing State The Kotlin Way
Zeyad Gasser
 
Saindo da zona de conforto… resolvi aprender android
Saindo da zona de conforto… resolvi aprender androidSaindo da zona de conforto… resolvi aprender android
Saindo da zona de conforto… resolvi aprender android
Daniel Baccin
 
DrupalCon jQuery
DrupalCon jQueryDrupalCon jQuery
DrupalCon jQuery
Nathan Smith
 
Strategies for Mitigating Complexity in React Based Redux Applicaitons
Strategies for Mitigating Complexity in React Based Redux ApplicaitonsStrategies for Mitigating Complexity in React Based Redux Applicaitons
Strategies for Mitigating Complexity in React Based Redux Applicaitons
garbles
 
AppForum 2014 Boost Hybrid App Performance
AppForum 2014 Boost Hybrid App PerformanceAppForum 2014 Boost Hybrid App Performance
AppForum 2014 Boost Hybrid App Performance
robgalvinjr
 
Modern Web Developement
Modern Web DevelopementModern Web Developement
Modern Web Developement
peychevi
 
Introductionandgreetings
IntroductionandgreetingsIntroductionandgreetings
Introductionandgreetings
Pozz ZaRat
 

Similar to Complex Architectures in Ember (20)

Knockout.js presentation
Knockout.js presentationKnockout.js presentation
Knockout.js presentation
 
Backbone
BackboneBackbone
Backbone
 
Dependency management & Package management in JavaScript
Dependency management & Package management in JavaScriptDependency management & Package management in JavaScript
Dependency management & Package management in JavaScript
 
Angular directive filter and routing
Angular directive filter and routingAngular directive filter and routing
Angular directive filter and routing
 
Design Patterns for Tablets and Smartphones
Design Patterns for Tablets and SmartphonesDesign Patterns for Tablets and Smartphones
Design Patterns for Tablets and Smartphones
 
Desenvolvendo uma aplicação híbrida para Android e IOs utilizando Ionic, aces...
Desenvolvendo uma aplicação híbrida para Android e IOs utilizando Ionic, aces...Desenvolvendo uma aplicação híbrida para Android e IOs utilizando Ionic, aces...
Desenvolvendo uma aplicação híbrida para Android e IOs utilizando Ionic, aces...
 
Design for succcess with react and storybook.js
Design for succcess with react and storybook.jsDesign for succcess with react and storybook.js
Design for succcess with react and storybook.js
 
Android app development basics
Android app development basicsAndroid app development basics
Android app development basics
 
Angular Workshop_Sarajevo2
Angular Workshop_Sarajevo2Angular Workshop_Sarajevo2
Angular Workshop_Sarajevo2
 
Ngrx slides
Ngrx slidesNgrx slides
Ngrx slides
 
Android 3
Android 3Android 3
Android 3
 
Google analytics
Google analyticsGoogle analytics
Google analytics
 
Touch/Mobile Websites with jQuery Mobile - Boise Code Camp 2013
Touch/Mobile Websites with jQuery Mobile - Boise Code Camp 2013Touch/Mobile Websites with jQuery Mobile - Boise Code Camp 2013
Touch/Mobile Websites with jQuery Mobile - Boise Code Camp 2013
 
MVI - Managing State The Kotlin Way
MVI - Managing State The Kotlin WayMVI - Managing State The Kotlin Way
MVI - Managing State The Kotlin Way
 
Saindo da zona de conforto… resolvi aprender android
Saindo da zona de conforto… resolvi aprender androidSaindo da zona de conforto… resolvi aprender android
Saindo da zona de conforto… resolvi aprender android
 
DrupalCon jQuery
DrupalCon jQueryDrupalCon jQuery
DrupalCon jQuery
 
Strategies for Mitigating Complexity in React Based Redux Applicaitons
Strategies for Mitigating Complexity in React Based Redux ApplicaitonsStrategies for Mitigating Complexity in React Based Redux Applicaitons
Strategies for Mitigating Complexity in React Based Redux Applicaitons
 
AppForum 2014 Boost Hybrid App Performance
AppForum 2014 Boost Hybrid App PerformanceAppForum 2014 Boost Hybrid App Performance
AppForum 2014 Boost Hybrid App Performance
 
Modern Web Developement
Modern Web DevelopementModern Web Developement
Modern Web Developement
 
Introductionandgreetings
IntroductionandgreetingsIntroductionandgreetings
Introductionandgreetings
 

More from Matthew Beale

Ember.js Module Loading
Ember.js Module LoadingEmber.js Module Loading
Ember.js Module Loading
Matthew Beale
 
Interoperable Component Patterns
Interoperable Component PatternsInteroperable Component Patterns
Interoperable Component Patterns
Matthew Beale
 
Attribute actions
Attribute actionsAttribute actions
Attribute actions
Matthew Beale
 
The Hidden Power of HTMLBars (or, Scope in Ember.js Templates)
The Hidden Power of HTMLBars (or, Scope in Ember.js Templates)The Hidden Power of HTMLBars (or, Scope in Ember.js Templates)
The Hidden Power of HTMLBars (or, Scope in Ember.js Templates)
Matthew Beale
 
Aligning Ember.js with Web Standards
Aligning Ember.js with Web StandardsAligning Ember.js with Web Standards
Aligning Ember.js with Web Standards
Matthew Beale
 
New Component Patterns in Ember.js
New Component Patterns in Ember.jsNew Component Patterns in Ember.js
New Component Patterns in Ember.js
Matthew Beale
 
Scalable vector ember
Scalable vector emberScalable vector ember
Scalable vector ember
Matthew Beale
 
Snappy Means Happy: Performance in Ember Apps
Snappy Means Happy: Performance in Ember AppsSnappy Means Happy: Performance in Ember Apps
Snappy Means Happy: Performance in Ember Apps
Matthew Beale
 
Client-side Auth with Ember.js
Client-side Auth with Ember.jsClient-side Auth with Ember.js
Client-side Auth with Ember.js
Matthew Beale
 

More from Matthew Beale (9)

Ember.js Module Loading
Ember.js Module LoadingEmber.js Module Loading
Ember.js Module Loading
 
Interoperable Component Patterns
Interoperable Component PatternsInteroperable Component Patterns
Interoperable Component Patterns
 
Attribute actions
Attribute actionsAttribute actions
Attribute actions
 
The Hidden Power of HTMLBars (or, Scope in Ember.js Templates)
The Hidden Power of HTMLBars (or, Scope in Ember.js Templates)The Hidden Power of HTMLBars (or, Scope in Ember.js Templates)
The Hidden Power of HTMLBars (or, Scope in Ember.js Templates)
 
Aligning Ember.js with Web Standards
Aligning Ember.js with Web StandardsAligning Ember.js with Web Standards
Aligning Ember.js with Web Standards
 
New Component Patterns in Ember.js
New Component Patterns in Ember.jsNew Component Patterns in Ember.js
New Component Patterns in Ember.js
 
Scalable vector ember
Scalable vector emberScalable vector ember
Scalable vector ember
 
Snappy Means Happy: Performance in Ember Apps
Snappy Means Happy: Performance in Ember AppsSnappy Means Happy: Performance in Ember Apps
Snappy Means Happy: Performance in Ember Apps
 
Client-side Auth with Ember.js
Client-side Auth with Ember.jsClient-side Auth with Ember.js
Client-side Auth with Ember.js
 

Recently uploaded

Top IPTV UK Providers of A Comprehensive Review.pdf
Top IPTV UK Providers of A Comprehensive Review.pdfTop IPTV UK Providers of A Comprehensive Review.pdf
Top IPTV UK Providers of A Comprehensive Review.pdf
Xtreame HDTV
 
高仿(nyu毕业证书)美国纽约大学毕业证文凭毕业证原版一模一样
高仿(nyu毕业证书)美国纽约大学毕业证文凭毕业证原版一模一样高仿(nyu毕业证书)美国纽约大学毕业证文凭毕业证原版一模一样
高仿(nyu毕业证书)美国纽约大学毕业证文凭毕业证原版一模一样
9u08k0x
 
Snoopy boards the big bow wow musical __
Snoopy boards the big bow wow musical __Snoopy boards the big bow wow musical __
Snoopy boards the big bow wow musical __
catcabrera
 
Orpah Winfrey Dwayne Johnson: Titans of Influence and Inspiration
Orpah Winfrey Dwayne Johnson: Titans of Influence and InspirationOrpah Winfrey Dwayne Johnson: Titans of Influence and Inspiration
Orpah Winfrey Dwayne Johnson: Titans of Influence and Inspiration
greendigital
 
_7 OTT App Builders to Support the Development of Your Video Applications_.pdf
_7 OTT App Builders to Support the Development of Your Video Applications_.pdf_7 OTT App Builders to Support the Development of Your Video Applications_.pdf
_7 OTT App Builders to Support the Development of Your Video Applications_.pdf
Mega P
 
The Evolution of the Leonardo DiCaprio Haircut: A Journey Through Style and C...
The Evolution of the Leonardo DiCaprio Haircut: A Journey Through Style and C...The Evolution of the Leonardo DiCaprio Haircut: A Journey Through Style and C...
The Evolution of the Leonardo DiCaprio Haircut: A Journey Through Style and C...
greendigital
 
240529_Teleprotection Global Market Report 2024.pdf
240529_Teleprotection Global Market Report 2024.pdf240529_Teleprotection Global Market Report 2024.pdf
240529_Teleprotection Global Market Report 2024.pdf
Madhura TBRC
 
定制(uow毕业证书)卧龙岗大学毕业证文凭学位证书原版一模一样
定制(uow毕业证书)卧龙岗大学毕业证文凭学位证书原版一模一样定制(uow毕业证书)卧龙岗大学毕业证文凭学位证书原版一模一样
定制(uow毕业证书)卧龙岗大学毕业证文凭学位证书原版一模一样
0md20cgg
 
原版制作(Mercer毕业证书)摩斯大学毕业证在读证明一模一样
原版制作(Mercer毕业证书)摩斯大学毕业证在读证明一模一样原版制作(Mercer毕业证书)摩斯大学毕业证在读证明一模一样
原版制作(Mercer毕业证书)摩斯大学毕业证在读证明一模一样
mul1kv5w
 
哪里买(osu毕业证书)美国俄勒冈州立大学毕业证双学位证书原版一模一样
哪里买(osu毕业证书)美国俄勒冈州立大学毕业证双学位证书原版一模一样哪里买(osu毕业证书)美国俄勒冈州立大学毕业证双学位证书原版一模一样
哪里买(osu毕业证书)美国俄勒冈州立大学毕业证双学位证书原版一模一样
9u08k0x
 
From Swing Music to Big Band Fame_ 5 Iconic Artists.pptx
From Swing Music to Big Band Fame_ 5 Iconic Artists.pptxFrom Swing Music to Big Band Fame_ 5 Iconic Artists.pptx
From Swing Music to Big Band Fame_ 5 Iconic Artists.pptx
Swing Street Radio
 
Modern Radio Frequency Access Control Systems: The Key to Efficiency and Safety
Modern Radio Frequency Access Control Systems: The Key to Efficiency and SafetyModern Radio Frequency Access Control Systems: The Key to Efficiency and Safety
Modern Radio Frequency Access Control Systems: The Key to Efficiency and Safety
AITIX LLC
 
Meet Dinah Mattingly – Larry Bird’s Partner in Life and Love
Meet Dinah Mattingly – Larry Bird’s Partner in Life and LoveMeet Dinah Mattingly – Larry Bird’s Partner in Life and Love
Meet Dinah Mattingly – Larry Bird’s Partner in Life and Love
get joys
 
The Unbelievable Tale of Dwayne Johnson Kidnapping: A Riveting Saga
The Unbelievable Tale of Dwayne Johnson Kidnapping: A Riveting SagaThe Unbelievable Tale of Dwayne Johnson Kidnapping: A Riveting Saga
The Unbelievable Tale of Dwayne Johnson Kidnapping: A Riveting Saga
greendigital
 
Christian Louboutin: Innovating with Red Soles
Christian Louboutin: Innovating with Red SolesChristian Louboutin: Innovating with Red Soles
Christian Louboutin: Innovating with Red Soles
get joys
 
Unveiling Paul Haggis Shaping Cinema Through Diversity. .pdf
Unveiling Paul Haggis Shaping Cinema Through Diversity. .pdfUnveiling Paul Haggis Shaping Cinema Through Diversity. .pdf
Unveiling Paul Haggis Shaping Cinema Through Diversity. .pdf
kenid14983
 
Matt Rife Cancels Shows Due to Health Concerns, Reschedules Tour Dates.pdf
Matt Rife Cancels Shows Due to Health Concerns, Reschedules Tour Dates.pdfMatt Rife Cancels Shows Due to Health Concerns, Reschedules Tour Dates.pdf
Matt Rife Cancels Shows Due to Health Concerns, Reschedules Tour Dates.pdf
Azura Everhart
 
Divertidamente SLIDE muito lindo e criativo, pptx
Divertidamente SLIDE muito lindo e criativo, pptxDivertidamente SLIDE muito lindo e criativo, pptx
Divertidamente SLIDE muito lindo e criativo, pptx
lunaemel03
 
Authenticity in Motion Pictures: How Steve Greisen Retains Real Stories
Authenticity in Motion Pictures: How Steve Greisen Retains Real StoriesAuthenticity in Motion Pictures: How Steve Greisen Retains Real Stories
Authenticity in Motion Pictures: How Steve Greisen Retains Real Stories
Steve Greisen
 
DIGIDEVTV A New area of OTT Distribution
DIGIDEVTV  A New area of OTT DistributionDIGIDEVTV  A New area of OTT Distribution
DIGIDEVTV A New area of OTT Distribution
joeqsm
 

Recently uploaded (20)

Top IPTV UK Providers of A Comprehensive Review.pdf
Top IPTV UK Providers of A Comprehensive Review.pdfTop IPTV UK Providers of A Comprehensive Review.pdf
Top IPTV UK Providers of A Comprehensive Review.pdf
 
高仿(nyu毕业证书)美国纽约大学毕业证文凭毕业证原版一模一样
高仿(nyu毕业证书)美国纽约大学毕业证文凭毕业证原版一模一样高仿(nyu毕业证书)美国纽约大学毕业证文凭毕业证原版一模一样
高仿(nyu毕业证书)美国纽约大学毕业证文凭毕业证原版一模一样
 
Snoopy boards the big bow wow musical __
Snoopy boards the big bow wow musical __Snoopy boards the big bow wow musical __
Snoopy boards the big bow wow musical __
 
Orpah Winfrey Dwayne Johnson: Titans of Influence and Inspiration
Orpah Winfrey Dwayne Johnson: Titans of Influence and InspirationOrpah Winfrey Dwayne Johnson: Titans of Influence and Inspiration
Orpah Winfrey Dwayne Johnson: Titans of Influence and Inspiration
 
_7 OTT App Builders to Support the Development of Your Video Applications_.pdf
_7 OTT App Builders to Support the Development of Your Video Applications_.pdf_7 OTT App Builders to Support the Development of Your Video Applications_.pdf
_7 OTT App Builders to Support the Development of Your Video Applications_.pdf
 
The Evolution of the Leonardo DiCaprio Haircut: A Journey Through Style and C...
The Evolution of the Leonardo DiCaprio Haircut: A Journey Through Style and C...The Evolution of the Leonardo DiCaprio Haircut: A Journey Through Style and C...
The Evolution of the Leonardo DiCaprio Haircut: A Journey Through Style and C...
 
240529_Teleprotection Global Market Report 2024.pdf
240529_Teleprotection Global Market Report 2024.pdf240529_Teleprotection Global Market Report 2024.pdf
240529_Teleprotection Global Market Report 2024.pdf
 
定制(uow毕业证书)卧龙岗大学毕业证文凭学位证书原版一模一样
定制(uow毕业证书)卧龙岗大学毕业证文凭学位证书原版一模一样定制(uow毕业证书)卧龙岗大学毕业证文凭学位证书原版一模一样
定制(uow毕业证书)卧龙岗大学毕业证文凭学位证书原版一模一样
 
原版制作(Mercer毕业证书)摩斯大学毕业证在读证明一模一样
原版制作(Mercer毕业证书)摩斯大学毕业证在读证明一模一样原版制作(Mercer毕业证书)摩斯大学毕业证在读证明一模一样
原版制作(Mercer毕业证书)摩斯大学毕业证在读证明一模一样
 
哪里买(osu毕业证书)美国俄勒冈州立大学毕业证双学位证书原版一模一样
哪里买(osu毕业证书)美国俄勒冈州立大学毕业证双学位证书原版一模一样哪里买(osu毕业证书)美国俄勒冈州立大学毕业证双学位证书原版一模一样
哪里买(osu毕业证书)美国俄勒冈州立大学毕业证双学位证书原版一模一样
 
From Swing Music to Big Band Fame_ 5 Iconic Artists.pptx
From Swing Music to Big Band Fame_ 5 Iconic Artists.pptxFrom Swing Music to Big Band Fame_ 5 Iconic Artists.pptx
From Swing Music to Big Band Fame_ 5 Iconic Artists.pptx
 
Modern Radio Frequency Access Control Systems: The Key to Efficiency and Safety
Modern Radio Frequency Access Control Systems: The Key to Efficiency and SafetyModern Radio Frequency Access Control Systems: The Key to Efficiency and Safety
Modern Radio Frequency Access Control Systems: The Key to Efficiency and Safety
 
Meet Dinah Mattingly – Larry Bird’s Partner in Life and Love
Meet Dinah Mattingly – Larry Bird’s Partner in Life and LoveMeet Dinah Mattingly – Larry Bird’s Partner in Life and Love
Meet Dinah Mattingly – Larry Bird’s Partner in Life and Love
 
The Unbelievable Tale of Dwayne Johnson Kidnapping: A Riveting Saga
The Unbelievable Tale of Dwayne Johnson Kidnapping: A Riveting SagaThe Unbelievable Tale of Dwayne Johnson Kidnapping: A Riveting Saga
The Unbelievable Tale of Dwayne Johnson Kidnapping: A Riveting Saga
 
Christian Louboutin: Innovating with Red Soles
Christian Louboutin: Innovating with Red SolesChristian Louboutin: Innovating with Red Soles
Christian Louboutin: Innovating with Red Soles
 
Unveiling Paul Haggis Shaping Cinema Through Diversity. .pdf
Unveiling Paul Haggis Shaping Cinema Through Diversity. .pdfUnveiling Paul Haggis Shaping Cinema Through Diversity. .pdf
Unveiling Paul Haggis Shaping Cinema Through Diversity. .pdf
 
Matt Rife Cancels Shows Due to Health Concerns, Reschedules Tour Dates.pdf
Matt Rife Cancels Shows Due to Health Concerns, Reschedules Tour Dates.pdfMatt Rife Cancels Shows Due to Health Concerns, Reschedules Tour Dates.pdf
Matt Rife Cancels Shows Due to Health Concerns, Reschedules Tour Dates.pdf
 
Divertidamente SLIDE muito lindo e criativo, pptx
Divertidamente SLIDE muito lindo e criativo, pptxDivertidamente SLIDE muito lindo e criativo, pptx
Divertidamente SLIDE muito lindo e criativo, pptx
 
Authenticity in Motion Pictures: How Steve Greisen Retains Real Stories
Authenticity in Motion Pictures: How Steve Greisen Retains Real StoriesAuthenticity in Motion Pictures: How Steve Greisen Retains Real Stories
Authenticity in Motion Pictures: How Steve Greisen Retains Real Stories
 
DIGIDEVTV A New area of OTT Distribution
DIGIDEVTV  A New area of OTT DistributionDIGIDEVTV  A New area of OTT Distribution
DIGIDEVTV A New area of OTT Distribution
 

Complex Architectures in Ember

  • 1. Hi. I’m Matthew. I build spiffy apps for clients in NYC Thursday, September 19, 13
  • 3. Let’s go single page Thursday, September 19, 13
  • 9. 1 <div style="clear:both"> 2 <div style="float:left"> 3 {{input value=title}} 4 {{textarea value=body}} 5 </div> 6 <div style="float:left"> 7 {{post-preview markdown=body}} 8 </div> 9 </div> 10 11 <div style="clear:both"> 12 <button style="float:left" {{action "preview"}}>Preview</button> 13 <button style="float:left" {{action "submit"}}>Submit</button> 14 </div> Thursday, September 19, 13
  • 14. 1 <div style="clear:both"> 2 <div style="float:left"> 3 {{input value=title}} 4 {{textarea value=body}} 5 </div> 6 <div style="float:left"> 7 {{post-preview markdown=body}} 8 </div> 9 </div> 10 11 <div style="clear:both"> 12 <button style="float:left" {{action "preview"}}>Preview</button> 13 <button style="float:left" {{action "submit"}}>Submit</button> 14 </div> ACTION DOESNT TALK TO COMPONENTS Thursday, September 19, 13
  • 15. 1 <div style="clear:both"> 2 <div style="float:left"> 3 {{input value=title}} 4 {{textarea value=body}} 5 </div> 6 <div style="float:left"> 7 {{post-preview markdown=body}} 8 </div> 9 </div> 10 11 <div style="clear:both"> 12 <button style="float:left" {{action "preview"}}>Preview</button> 13 <button style="float:left" {{action "submit"}}>Submit</button> 14 </div> CHASM OF DOM Thursday, September 19, 13
  • 16. 1 <div style="clear:both"> 2 <div style="float:left"> 3 {{input value=title}} 4 {{textarea value=body}} 5 </div> 6 <div style="float:left"> 7 {{post-preview markdown=body viewName="preview"}} 8 </div> 9 </div> 10 11 <div style="clear:both"> 12 <button style="float:left" {{action "preview" target=view.preview}}>Preview</button> 13 <button style="float:left" {{action "submit"}}>Submit</button> 14 </div> WORKAROUND 1 Thursday, September 19, 13
  • 17. 1 <div style="clear:both"> 2 <div style="float:left"> 3 {{input value=title}} 4 {{textarea value=body}} 5 </div> 6 <div style="float:left"> 7 {{view App.PostPreview markdownBinding=body viewName="preview"}} 8 </div> 9 </div> 10 11 <div style="clear:both"> 12 <button style="float:left" {{action "preview" target=view.preview}}>Preview</button> 13 <button style="float:left" {{action "submit"}}>Submit</button> 14 </div> WORKAROUND 2 Thursday, September 19, 13
  • 18. 1 <div style="clear:both"> 2 <div style="float:left"> 3 {{input value=title}} 4 {{textarea value=body}} 5 </div> 6 <div style="float:left"> 7 {{render "post_preview" body}} 8 </div> 9 </div> 10 11 <div style="clear:both"> 12 <button style="float:left" {{action "preview"}}>Preview</button> 13 <button style="float:left" {{action "submit"}}>Submit</button> 14 </div> 1 App.ApplicationRoute = Ember.Route.extend({ 2 actions: { 3 preview: function(){ 4 var controller = this.controllerFor('post_preview'); 5 controller.updatePreview(); 6 } 7 } 8 }); WORKAROUND 3 Thursday, September 19, 13
  • 19. WORKAROUND 4 1 App.ApplicationRoute = Ember.Route.extend({ 2 renderTemplate: function(){ 3 this._super.apply(this, arguments); 4 this.render('post_preview', { 5 into: 'application', 6 outlet: 'preview', 7 controller: 'post_preview' 8 }); 9 }, 10 actions: { 11 preview: function(){ 12 var app = this.controllerFor('application'); 13 var preview = this.controllerFor('post_preview'); 14 preview.set('markdown', app.get('body')); 15 } 16 } 17 }); 18 19 App.PostPreviewController = Ember.Controller.extend(); 1 <div style="clear:both"> 2 <div style="float:left"> 3 {{input value=title}} 4 {{textarea value=body}} 5 </div> 6 <div style="float:left"> 7 {{outlet "preview"}} 8 </div> 9 </div> 10 11 <div style="clear:both"> 12 <button style="float:left" {{action "preview"}}>Preview</button> 13 <button style="float:left" {{action "submit"}}>Submit</button> 14 </div> Thursday, September 19, 13
  • 20. When we pick between these options... Thursday, September 19, 13
  • 21. We make design decisions. Thursday, September 19, 13
  • 22. •Re-usability as ui component •re-usability as action •If an action fires •Where the action is handled •The internals of preview Thursday, September 19, 13
  • 24. Architecture in Ember apps is dictated by routes and templates. Thursday, September 19, 13
  • 25. Routes and templates decide how actions propagate the controller/route tree, scope access to dependencies, and are most subject to external constraints. Thursday, September 19, 13
  • 26. Routes and templates decide how actions propagate the controller/route tree, scope access to dependencies, and are most subject to external constraints. Thursday, September 19, 13
  • 27. Routes and templates decide how actions propagate the controller/route tree, scope access to dependencies, and are most subject to external constraints. Thursday, September 19, 13
  • 28. Routes and templates decide how actions propagate the controller/route tree, scope access to dependencies, and are most subject to external constraints. Thursday, September 19, 13
  • 29. Routes and templates decide how actions propagate the controller/route tree, scope access to dependencies, and are most subject to external constraints. Thursday, September 19, 13
  • 30. “Understanding actions in two easy steps” Thursday, September 19, 13
  • 32. WARNING THEse slides describe the behavior IN rc8 and beyond. behavior before the changes in rc8 is very similar to what is described here, but not identical. Thursday, September 19, 13
  • 33. ACTION BUBBLING 1 var Actionable = Ember.Object.extend(Ember.ActionHandler); 2 3 var firstTarget = Actionable.create(); 4 5 firstTarget.send("Wie Geht's"); 6 7 // Nothing! Thursday, September 19, 13
  • 34. ACTION BUBBLING 1 var Actionable = Ember.Object.extend(Ember.ActionHandler); 2 3 var firstTarget = Actionable.extend({ 4 actions: { 5 "Wie Geht's": function(){ 6 console.log("Danke gut"); 7 } 8 } 9 }).create(); 10 11 firstTarget.send("Wie Geht's"); 12 13 // Danke gut Thursday, September 19, 13
  • 35. ACTION BUBBLING 1 var Actionable = Ember.Object.extend(Ember.ActionHandler); 2 3 var secondTarget = Actionable.extend({ 4 actions: { 5 "Wie Geht's": function(){ 6 console.log("Und dir?"); 7 } 8 } 9 }).create(); 10 11 var firstTarget = Actionable.extend({ 12 target: secondTarget, 13 actions: { 14 "Wie Geht's": function(){ 15 console.log("Danke gut"); 16 } 17 } 18 }).create(); 19 20 firstTarget.send("Wie Geht's"); 21 22 // Danke gut Thursday, September 19, 13
  • 36. ACTION BUBBLING 1 var Actionable = Ember.Object.extend(Ember.ActionHandler); 2 3 var secondTarget = Actionable.extend({ 4 actions: { 5 "Wie Geht's": function(){ 6 console.log("Und dir?"); 7 } 8 } 9 }).create(); 10 11 var firstTarget = Actionable.extend({ 12 target: secondTarget, 13 actions: { 14 "Wie Geht's": function(){ 15 console.log("Danke gut"); 16 return true; 17 } 18 } 19 }).create(); 20 21 firstTarget.send("Wie Geht's"); 22 23 // Danke gut 24 // Und dir? RETUrn true to continue bubbling the action Thursday, September 19, 13
  • 37. ACTION BUBBLING 1 var Actionable = Ember.Object.extend(Ember.ActionHandler); 2 3 var secondTarget = Actionable.extend({ 4 actions: { 5 "Wie Geht's": function(){ 6 console.log("Und dir?"); 7 } 8 } 9 }).create(); 10 11 var firstTarget = Actionable.extend({ 12 target: secondTarget, 13 actions: { 14 "Wie Geht's": null, // Or just don't define actions 15 } 16 }).create(); 17 18 firstTarget.send("Wie Geht's"); 19 20 // Und dir? Thursday, September 19, 13
  • 38. Controllers, Routes, Views, and Components handle actions. Thursday, September 19, 13
  • 39. Only Controllers and Routes have targets for bubbling. Thursday, September 19, 13
  • 40. #1: ROUTES ARE stateS. Kind of. Thursday, September 19, 13
  • 41. ROUTES ARE STATES1 var moodManager = Ember.StateManager.create({ 2 initialState: 'good', 3 good: Ember.State.create({ 4 gut: function(){ 5 console.log('Ja'); 6 } 7 }), 8 bad: Ember.State.create({ 9 gut: function(){ 10 console.log('Nein'); 11 } 12 }), 13 quiet: Ember.State.create() 14 }); 15 16 moodManager.send('gut'); 17 // Ja 18 19 moodManager.transitionTo('bad'); 20 moodManager.send('gut'); 21 // Nein 22 23 moodManager.transitionTo('quiet'); 24 moodManager.send('gut'); 25 // Uncaught Error: <Ember.StateManager:ember138> could not respond to event gut in state quiet. Thursday, September 19, 13
  • 42. ROUTES ARE STATES1 App = Ember.Application.create(); 2 3 App.Router.map(function(){ 4 this.route('good'); 5 this.route('bad'); 6 this.route('quiet'); 7 }); 8 9 App.GoodRoute = Ember.Route.extend({ 10 actions: { gut: function(){ console.log('Ja'); } } 11 }); 12 13 App.BadRoute = Ember.Route.extend({ 14 actions: { gut: function(){ console.log('Nein'); } } 15 }); 16 17 App.QuietRoute = Ember.Route.extend(); 1 {{! application.hbs }} 2 <a {{action "gut"}}>Gut?</a> 3 {{#link-to "good"}}Get happy{{/link-to}} 4 {{#link-to "bad"}}Get sour{{/link-to}} 5 {{#link-to "quiet"}}Get quiet{{/link-to}} Thursday, September 19, 13
  • 43. ROUTES ARE STATES1 App = Ember.Application.create(); 2 3 App.Router.map(function(){ 4 this.route('good'); 5 this.route('bad'); 6 this.route('quiet'); 7 }); 8 9 App.GoodRoute = Ember.Route.extend({ 10 actions: { gut: function(){ console.log('Ja'); } } 11 }); 12 13 App.BadRoute = Ember.Route.extend({ 14 actions: { gut: function(){ console.log('Nein'); } } 15 }); 16 17 App.QuietRoute = Ember.Route.extend(); 1 {{! application.hbs }} 2 <a {{action "gut"}}>Gut?</a> 3 {{#link-to "good"}}Get happy{{/link-to}} 4 {{#link-to "bad"}}Get sour{{/link-to}} 5 {{#link-to "quiet"}}Get quiet{{/link-to}} ACTIOns always hit the leaf route, regardless of where they fire from Thursday, September 19, 13
  • 44. ROUTES ARE STATES 1 App = Ember.Application.create(); 2 3 App.Router.map(function(){ 4 this.route('good'); 5 this.route('bad'); 6 this.route('quiet'); 7 }); 8 9 App.GoodRoute = Ember.Route.extend({ 10 actions: { gut: function(){ console.log('Ja'); } } 11 }); 12 13 App.GoodController = Ember.Controller.extend({ 14 actions: { gut: function(){ console.log('ignored :-('); } } 15 }); 1 {{! application.hbs }} 2 <a {{action "gut"}}>Gut?</a> 3 {{#link-to "good"}}Get happy{{/link-to}} 4 {{#link-to "bad"}}Get sour{{/link-to}} 5 {{#link-to "quiet"}}Get quiet{{/link-to}} BUT the TEMPLATE DECIDES WHICH CONTROLLERS SEE THAT ACTION Thursday, September 19, 13
  • 45. ACTIONS ON CONTROLLERS •couples template to controller •should not force use of NEEDs ACTIONS ON routes •have access to all controllers •handled from any template on a page Thursday, September 19, 13
  • 46. Choose where to put an action. Thursday, September 19, 13
  • 47. Routes and templates decide how actions propagate the controller/route tree, scope access to dependencies, and are most subject to external constraints. Thursday, September 19, 13
  • 48. 1 <div style="clear:both"> 2 <div style="float:left"> 3 {{input value=title}} 4 {{textarea value=body}} 5 </div> 6 <div style="float:left"> 7 {{post-preview markdown=body viewName="preview"}} 8 </div> 9 </div> 10 11 <div style="clear:both"> 12 <button style="float:left" {{action "preview" target=view.preview}}>Preview</button> 13 <button style="float:left" {{action "submit"}}>Submit</button> 14 </div> setting viewName causes a property named “preview” to be added on the parentview of that view with it’s own instance that “preview” property can be set as a target Thursday, September 19, 13
  • 49. •Components access nothing •views access parentView, controller •controllers access A target (the route or a parent controller) AND OTHER CONTROLLERS via needs •routes access all controllers and models •CHEAT WITH REGISTER/INJECT Thursday, September 19, 13
  • 50. CHEAT WITH REGISTER/INJECT 1 App = Ember.Application.create(); 2 3 App.inject('route', 'session', 'controller:session'); 4 5 App.IndexRoute = Ember.Route.extend({ 6 beforeModel: function(){ 7 console.log( this.get('session.user.name') ); 8 } 9 }); 10 11 App.SessionController = Ember.Controller.extend({ 12 user: { name: 'Bob' } 13 }); Thursday, September 19, 13
  • 51. 1 {{render "post"}} 2 {{render "post" post}} 3 {{component content=post}} 4 {{view App.PostView contentBinding="post"}} 5 {{template "post"}} THIS dictates part of your architecture Thursday, September 19, 13
  • 52. When confused about an app, look to the templates and the routes first. Thursday, September 19, 13
  • 53. “Controllers have lots of features!” AKA BUT PLEASE DON’t MAKE THEM CLEVER Thursday, September 19, 13
  • 54. “I AM SO CLEVER THAT SOMETIMES I DON’T UNDERSTAND A SINGLE WORD OF WHAT I AM SAYING” Oscar Wilde Thursday, September 19, 13
  • 55. Clever Controller 1 1 App.BooksController = Ember.ArrayController.extend({ 2 needs: ['library'], 3 content: Em.computed.alias('controllers.library.books') 4 }); Thursday, September 19, 13
  • 56. Clever Controller 1 1 App.BooksController = Ember.ArrayController.extend({ 2 needs: ['library'], 3 content: Em.computed.alias('controllers.library.books') 4 }); assumption about library controller Assumed to only be attached to a route (no item controller) assumes books belong to a single library Thursday, September 19, 13
  • 57. LESS Clever Controller 1 1 App.BooksRoute = Ember.Route.extend({ 2 model: function(){ 3 this.modelFor('library').get('books') 4 } 5 }); 6 7 // The Ember controller provided by convention is sufficient. Thursday, September 19, 13
  • 58. 1 <div> 2 <ul class="tabs"> 3 <li {{action "openSignIn"}}>Sign In</li> 4 <li {{action "openSignUp"}}>Sign Up</li> 5 <li {{action "openForgotPassword"}}>Forgot Password</li> 6 </ul> 7 {{#if isSignInOpen}}{{template "sign_in"}}{{/if}} 8 {{#if isSignUpOpen}}{{template "sign_up"}}{{/if}} 9 {{#if isForgotPasswordOpen}}{{template "forgot_password"}}{{/if}} 10 </div> Clever Controller 2 1 App.SessionController = Em.Controller.extend({ 2 isSignInOpen: false, 3 isSignUpOpen: false, 4 isForgotPasswordOpen: false, 5 6 actions: { 7 closeOptions: function(){ 8 this.setProperties({ 9 isSignInOpen: false, 10 isSignUpOpen: false, 11 isForgotPasswordOpen: false 12 }); 13 }, 14 openSignIn: function(){ this.closeOptions(); this.set('isSignUpOpen', true); }, 15 openSignUp: function(){ this.closeOptions(); this.set('isSignUpOpen', true); }, 16 openForgotPassword: function(){ this.closeOptions(); this.set('isForgotPasswordOpen', true); } 17 } 18 }); Thursday, September 19, 13
  • 59. 1 <div> 2 <ul class="tabs"> 3 <li {{action "openSignIn"}}>Sign In</li> 4 <li {{action "openSignUp"}}>Sign Up</li> 5 <li {{action "openForgotPassword"}}>Forgot Password</li> 6 </ul> 7 {{#if isSignInOpen}}{{template "sign_in"}}{{/if}} 8 {{#if isSignUpOpen}}{{template "sign_up"}}{{/if}} 9 {{#if isForgotPasswordOpen}}{{template "forgot_password"}}{{/if}} 10 </div> Clever Controller 2 1 App.SessionController = Em.Controller.extend({ 2 isSignInOpen: false, 3 isSignUpOpen: false, 4 isForgotPasswordOpen: false, 5 6 actions: { 7 closeOptions: function(){ 8 this.setProperties({ 9 isSignInOpen: false, 10 isSignUpOpen: false, 11 isForgotPasswordOpen: false 12 }); 13 }, 14 openSignIn: function(){ this.closeOptions(); this.set('isSignUpOpen', true); }, 15 openSignUp: function(){ this.closeOptions(); this.set('isSignUpOpen', true); }, 16 openForgotPassword: function(){ this.closeOptions(); this.set('isForgotPasswordOpen', true); } 17 } 18 }); NOT. VERY. DRY. NEW PANELS MUST BE ADDED ON COnTROLLER NEW PANELS MUST BE ADDED IN TEMPLATE Thursday, September 19, 13
  • 60. 1 <div> 2 <ul class="tabs"> 3 <li {{action "openSignIn"}}>Sign In</li> 4 <li {{action "openSignUp"}}>Sign Up</li> 5 <li {{action "openForgotPassword"}}>Forgot Password</li> 6 </ul> 7 {{#if isSignInOpen}}{{template "sign_in"}}{{/if}} 8 {{#if isSignUpOpen}}{{template "sign_up"}}{{/if}} 9 {{#if isForgotPasswordOpen}}{{template "forgot_password"}}{{/if}} 10 </div> Clever Controller 2 1 App.SessionController = Em.Controller.extend({ 2 isSignInOpen: false, 3 isSignUpOpen: false, 4 isForgotPasswordOpen: false, 5 6 actions: { 7 closeOptions: function(){ 8 this.setProperties({ 9 isSignInOpen: false, 10 isSignUpOpen: false, 11 isForgotPasswordOpen: false 12 }); 13 }, 14 openSignIn: function(){ this.closeOptions(); this.set('isSignUpOpen', true); }, 15 openSignUp: function(){ this.closeOptions(); this.set('isSignUpOpen', true); }, 16 openForgotPassword: function(){ this.closeOptions(); this.set('isForgotPasswordOpen', true); } 17 } 18 }); NAV & DISPLAYED PANEL TIGHTLY COUPLED panels cannot be controlled from other scopes Thursday, September 19, 13
  • 61. LESS Clever Controller 2 1 <div> 2 <ul class="tabs"> 3 <li {{bind-attr class="isSignInOpen:active"}}{{action "openPanel" "signIn"}}>Sign In</li> 4 <li {{bind-attr class="isSignUpOpen:active"}}{{action "openPanel" "signUp"}}>Sign Up</li> 5 <li {{bind-attr class="isForgotPasswordOpen:active"}}{{action "openPanel" "forgotPassword"}}>Forgot Passw 6 </ul> 7 {{outlet "panel"}} 8 </div> 1 App.SessionRoute = Ember.Router.extend({ 2 setupController: function(){ 3 this._super.apply(this, arguments); 4 Em.run.once(this, function(){ 5 this.send('openPanel', 'signIn'); 6 }); 7 }, 8 actions: { 9 openPanel: function(panel){ 10 this.controller.set('openPanel', panel); 11 this.render('panels/'+panel, { 12 into: 'session', 13 outlet: 'panel' 14 }); 15 } 16 } 17 }); 18 19 App.SessionController = Ember.Controller.extend({ 20 isSignInOpen: Em.computed.equal('openPanel', 'signIn'), 21 isSignUpOpen: Em.computed.equal('openPanel', 'signUp'), 22 isForgotPasswordOpen: Em.computed.equal('openPanel', 'forgotPassword') 23 }); Thursday, September 19, 13
  • 62. 1 {{#each controller}} 2 {{name}} 3 {{/each}} Clever Controller 3 1 App = Ember.Application.create(); 2 3 App.IndexRoute = Ember.Route.extend({ 4 model: function(){ 5 return Ember.A([ 6 { name: 'Munster' }, 7 { name: 'Alpine Lace' }, 8 { name: 'Tome' } 9 ]); 10 } 11 }); Thursday, September 19, 13
  • 63. 1 {{#each controller}} 2 {{name}} 3 {{/each}} Clever Controller 3 1 App = Ember.Application.create(); 2 3 App.IndexRoute = Ember.Route.extend({ 4 model: function(){ 5 return Ember.A([ 6 { name: 'Munster' }, 7 { name: 'Alpine Lace' }, 8 { name: 'Tome' } 9 ]); 10 } 11 }); APPle invasion! apple invasion! apple invasion! Thursday, September 19, 13
  • 64. 1 {{#each controller}} 2 {{name}} 3 {{/each}} Clever Controller 31 App = Ember.Application.create(); 2 3 App.IndexRoute = Ember.Route.extend({ 4 model: function(){ 5 return Ember.A([ 6 { name: 'Munster' }, 7 { name: 'Alpine Lace' }, 8 { name: 'Tome' } 9 ]); 10 } 11 }); 12 13 App.IndexController = Ember.ArrayController.extend({ 14 itemController: 'fruitInvasion' 15 }); 16 17 App.FruitInvasionController = Ember.ObjectController.extend({ 18 name: function(){ 19 return 'Apple invasion!'; 20 }.property() 21 }); APPle invasion! apple invasion! apple invasion! Changes context in the template from outside the template. Thursday, September 19, 13
  • 65. 1 {{#each controller itemController='fruitInvasion'}} 2 {{name}} 3 {{/each}} LESS Clever Controller 3 1 App = Ember.Application.create(); 2 3 App.IndexRoute = Ember.Route.extend({ 4 model: function(){ 5 return Ember.A([ 6 { name: 'Munster' }, 7 { name: 'Alpine Lace' }, 8 { name: 'Tome' } 9 ]); 10 } 11 }); 12 13 App.FruitInvasionController = Ember.ObjectController.extend({ 14 name: function(){ 15 return 'Apple invasion!'; 16 }.property() 17 }); Thursday, September 19, 13
  • 66. “TOO CLEVER IS DUMB” Ogden Nash Thursday, September 19, 13
  • 68. Don’t work so hard in controllers. Thursday, September 19, 13
  • 69. Look to routes and templates for your application architecture. Thursday, September 19, 13