SlideShare uma empresa Scribd logo
1 de 70
Baixar para ler offline
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

Mais conteúdo relacionado

Mais procurados

Workshop 14: AngularJS Parte III
Workshop 14: AngularJS Parte IIIWorkshop 14: AngularJS Parte III
Workshop 14: AngularJS Parte IIIVisual Engineering
 
Testing Ember Apps: Managing Dependency
Testing Ember Apps: Managing DependencyTesting Ember Apps: Managing Dependency
Testing Ember Apps: Managing DependencyMatthew 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 KarmaExoLeaders.com
 
Swift Delhi: Practical POP
Swift Delhi: Practical POPSwift Delhi: Practical POP
Swift Delhi: Practical POPNatasha Murashev
 
Patterns Are Good For Managers
Patterns Are Good For ManagersPatterns Are Good For Managers
Patterns Are Good For ManagersAgileThought
 
Practical Protocol-Oriented-Programming
Practical Protocol-Oriented-ProgrammingPractical Protocol-Oriented-Programming
Practical Protocol-Oriented-ProgrammingNatasha Murashev
 
Integrating React.js with PHP projects
Integrating React.js with PHP projectsIntegrating React.js with PHP projects
Integrating React.js with PHP projectsIgnacio Martín
 
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, HelsinkiRobert Nyman
 
Workshop 23: ReactJS, React & Redux testing
Workshop 23: ReactJS, React & Redux testingWorkshop 23: ReactJS, React & Redux testing
Workshop 23: ReactJS, React & Redux testingVisual Engineering
 
Backbone.js and friends
Backbone.js and friendsBackbone.js and friends
Backbone.js and friendsGood 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 IntroductionVisual 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 DevsRebecca 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 / underscoreNicolas Carlo
 
06 jQuery #burningkeyboards
06 jQuery  #burningkeyboards06 jQuery  #burningkeyboards
06 jQuery #burningkeyboardsDenis Ristic
 
Loadrunner
LoadrunnerLoadrunner
Loadrunnerdanwrong
 

Mais procurados (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
 

Destaque

Intro to emberjs
Intro to emberjsIntro to emberjs
Intro to emberjsMandy 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.jsLeo Hernandez
 
Parse Apps with Ember.js
Parse Apps with Ember.jsParse Apps with Ember.js
Parse Apps with Ember.jsMatthew Beale
 
Avoiding Common Pitfalls in Ember.js
Avoiding Common Pitfalls in Ember.jsAvoiding Common Pitfalls in Ember.js
Avoiding Common Pitfalls in Ember.jsAlex 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.jsMark Mansour
 
Architecture: ember.js and AngularJS
Architecture: ember.js and AngularJSArchitecture: ember.js and AngularJS
Architecture: ember.js and AngularJSlrdesign
 
Integrating Ember.js into legacy applications
Integrating Ember.js into legacy applicationsIntegrating Ember.js into legacy applications
Integrating Ember.js into legacy applicationsLevelbossMike
 
CSS Regression Tests with WebdriverCSS
CSS Regression Tests with WebdriverCSSCSS Regression Tests with WebdriverCSS
CSS Regression Tests with WebdriverCSSChristian Bromann
 
20120518 mssql table_schema_xml_namespace
20120518 mssql table_schema_xml_namespace20120518 mssql table_schema_xml_namespace
20120518 mssql table_schema_xml_namespaceLearningTech
 
electron for emberists
electron for emberistselectron for emberists
electron for emberistsAidan Nulman
 
Testing ember data transforms
Testing ember data transformsTesting ember data transforms
Testing ember data transformsSara Raasch
 
Ember Community 2016 - Be the Bark
Ember Community 2016 - Be the BarkEmber Community 2016 - Be the Bark
Ember Community 2016 - Be the BarkMatthew Beale
 
Velocity spa faster_092116
Velocity spa faster_092116Velocity spa faster_092116
Velocity spa faster_092116Manuel 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 EmberSara Raasch
 
LA Ember.js Meetup, Jan 2017
LA Ember.js Meetup, Jan 2017LA Ember.js Meetup, Jan 2017
LA Ember.js Meetup, Jan 2017Matthew Beale
 
Nest v. Flat with EmberData
Nest v. Flat with EmberDataNest v. Flat with EmberData
Nest v. Flat with EmberDataRyan M Harrison
 
Ember: Guts & Goals
Ember: Guts & GoalsEmber: Guts & Goals
Ember: Guts & GoalsBob Lail
 

Destaque (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
 

Semelhante a Complex Architectures in Ember

Knockout.js presentation
Knockout.js presentationKnockout.js presentation
Knockout.js presentationScott Messinger
 
Dependency management & Package management in JavaScript
Dependency management & Package management in JavaScriptDependency management & Package management in JavaScript
Dependency management & Package management in JavaScriptSebastiano Armeli
 
Angular directive filter and routing
Angular directive filter and routingAngular directive filter and routing
Angular directive filter and routingjagriti srivastava
 
Design Patterns for Tablets and Smartphones
Design Patterns for Tablets and SmartphonesDesign Patterns for Tablets and Smartphones
Design Patterns for Tablets and SmartphonesMichael 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.jsChris Saylor
 
Android app development basics
Android app development basicsAndroid app development basics
Android app development basicsAnton Narusberg
 
Google analytics
Google analyticsGoogle analytics
Google analyticsLo 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 2013Brett Adler
 
MVI - Managing State The Kotlin Way
MVI - Managing State The Kotlin WayMVI - Managing State The Kotlin Way
MVI - Managing State The Kotlin WayZeyad 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 androidDaniel Baccin
 
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 Applicaitonsgarbles
 
AppForum 2014 Boost Hybrid App Performance
AppForum 2014 Boost Hybrid App PerformanceAppForum 2014 Boost Hybrid App Performance
AppForum 2014 Boost Hybrid App Performancerobgalvinjr
 
Introductionandgreetings
IntroductionandgreetingsIntroductionandgreetings
IntroductionandgreetingsPozz ZaRat
 
Modern Web Developement
Modern Web DevelopementModern Web Developement
Modern Web Developementpeychevi
 

Semelhante a 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
 
Introductionandgreetings
IntroductionandgreetingsIntroductionandgreetings
Introductionandgreetings
 
Modern Web Developement
Modern Web DevelopementModern Web Developement
Modern Web Developement
 

Mais de Matthew Beale

Ember.js Module Loading
Ember.js Module LoadingEmber.js Module Loading
Ember.js Module LoadingMatthew Beale
 
Interoperable Component Patterns
Interoperable Component PatternsInteroperable Component Patterns
Interoperable Component PatternsMatthew 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 StandardsMatthew Beale
 
New Component Patterns in Ember.js
New Component Patterns in Ember.jsNew Component Patterns in Ember.js
New Component Patterns in Ember.jsMatthew Beale
 
Scalable vector ember
Scalable vector emberScalable vector ember
Scalable vector emberMatthew 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 AppsMatthew Beale
 
Client-side Auth with Ember.js
Client-side Auth with Ember.jsClient-side Auth with Ember.js
Client-side Auth with Ember.jsMatthew Beale
 

Mais de 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
 

Último

Call Girls Somajiguda Sarani 7001305949 all area service COD available Any Time
Call Girls Somajiguda Sarani 7001305949 all area service COD available Any TimeCall Girls Somajiguda Sarani 7001305949 all area service COD available Any Time
Call Girls Somajiguda Sarani 7001305949 all area service COD available Any Timedelhimodelshub1
 
QUIZ BOLLYWOOD ( weekly quiz ) - SJU quizzers
QUIZ BOLLYWOOD ( weekly quiz ) - SJU quizzersQUIZ BOLLYWOOD ( weekly quiz ) - SJU quizzers
QUIZ BOLLYWOOD ( weekly quiz ) - SJU quizzersSJU Quizzers
 
8377087607 Full Enjoy @24/7 Call Girls in Patel Nagar Delhi NCR
8377087607 Full Enjoy @24/7 Call Girls in Patel Nagar Delhi NCR8377087607 Full Enjoy @24/7 Call Girls in Patel Nagar Delhi NCR
8377087607 Full Enjoy @24/7 Call Girls in Patel Nagar Delhi NCRdollysharma2066
 
High Profile Call Girls Sodepur - 8250192130 Escorts Service with Real Photos...
High Profile Call Girls Sodepur - 8250192130 Escorts Service with Real Photos...High Profile Call Girls Sodepur - 8250192130 Escorts Service with Real Photos...
High Profile Call Girls Sodepur - 8250192130 Escorts Service with Real Photos...Riya Pathan
 
Call Girls Near Taurus Sarovar Portico Hotel New Delhi 9873777170
Call Girls Near Taurus Sarovar Portico Hotel New Delhi 9873777170Call Girls Near Taurus Sarovar Portico Hotel New Delhi 9873777170
Call Girls Near Taurus Sarovar Portico Hotel New Delhi 9873777170Sonam Pathan
 
Fun Call Girls In Goa 7028418221 Escort Service In Morjim Beach Call Girl
Fun Call Girls In Goa 7028418221 Escort Service In Morjim Beach Call GirlFun Call Girls In Goa 7028418221 Escort Service In Morjim Beach Call Girl
Fun Call Girls In Goa 7028418221 Escort Service In Morjim Beach Call GirlApsara Of India
 
VIP Call Girls In Goa 7028418221 Call Girls In Baga Beach Escorts Service
VIP Call Girls In Goa 7028418221 Call Girls In Baga Beach Escorts ServiceVIP Call Girls In Goa 7028418221 Call Girls In Baga Beach Escorts Service
VIP Call Girls In Goa 7028418221 Call Girls In Baga Beach Escorts ServiceApsara Of India
 
Vip Udaipur Call Girls 9602870969 Dabok Airport Udaipur Escorts Service
Vip Udaipur Call Girls 9602870969 Dabok Airport Udaipur Escorts ServiceVip Udaipur Call Girls 9602870969 Dabok Airport Udaipur Escorts Service
Vip Udaipur Call Girls 9602870969 Dabok Airport Udaipur Escorts ServiceApsara Of India
 
Housewife Call Girls Sonagachi - 8250192130 Booking and charges genuine rate ...
Housewife Call Girls Sonagachi - 8250192130 Booking and charges genuine rate ...Housewife Call Girls Sonagachi - 8250192130 Booking and charges genuine rate ...
Housewife Call Girls Sonagachi - 8250192130 Booking and charges genuine rate ...Riya Pathan
 
Kolkata Call Girl Howrah 👉 8250192130 ❣️💯 Available With Room 24×7
Kolkata Call Girl Howrah 👉 8250192130 ❣️💯 Available With Room 24×7Kolkata Call Girl Howrah 👉 8250192130 ❣️💯 Available With Room 24×7
Kolkata Call Girl Howrah 👉 8250192130 ❣️💯 Available With Room 24×7Riya Pathan
 
Air-Hostess Call Girls Shobhabazar | 8250192130 At Low Cost Cash Payment Booking
Air-Hostess Call Girls Shobhabazar | 8250192130 At Low Cost Cash Payment BookingAir-Hostess Call Girls Shobhabazar | 8250192130 At Low Cost Cash Payment Booking
Air-Hostess Call Girls Shobhabazar | 8250192130 At Low Cost Cash Payment BookingRiya Pathan
 
Hifi Laxmi Nagar Call Girls Service WhatsApp -> 9999965857 Available 24x7 ^ D...
Hifi Laxmi Nagar Call Girls Service WhatsApp -> 9999965857 Available 24x7 ^ D...Hifi Laxmi Nagar Call Girls Service WhatsApp -> 9999965857 Available 24x7 ^ D...
Hifi Laxmi Nagar Call Girls Service WhatsApp -> 9999965857 Available 24x7 ^ D...srsj9000
 
Hot Call Girls In Goa 7028418221 Call Girls In Vagator Beach EsCoRtS
Hot Call Girls In Goa 7028418221 Call Girls In Vagator Beach EsCoRtSHot Call Girls In Goa 7028418221 Call Girls In Vagator Beach EsCoRtS
Hot Call Girls In Goa 7028418221 Call Girls In Vagator Beach EsCoRtSApsara Of India
 
ViP Call Girls In Udaipur 9602870969 Gulab Bagh Escorts SeRvIcE
ViP Call Girls In Udaipur 9602870969 Gulab Bagh Escorts SeRvIcEViP Call Girls In Udaipur 9602870969 Gulab Bagh Escorts SeRvIcE
ViP Call Girls In Udaipur 9602870969 Gulab Bagh Escorts SeRvIcEApsara Of India
 
Cash Payment Contact:- 7028418221 Goa Call Girls Service North Goa Escorts
Cash Payment Contact:- 7028418221 Goa Call Girls Service North Goa EscortsCash Payment Contact:- 7028418221 Goa Call Girls Service North Goa Escorts
Cash Payment Contact:- 7028418221 Goa Call Girls Service North Goa EscortsApsara Of India
 
Call Girls Ellis Bridge 7397865700 Independent Call Girls
Call Girls Ellis Bridge 7397865700 Independent Call GirlsCall Girls Ellis Bridge 7397865700 Independent Call Girls
Call Girls Ellis Bridge 7397865700 Independent Call Girlsssuser7cb4ff
 
Call Girls in Najafgarh Delhi 💯Call Us 🔝8264348440🔝
Call Girls in Najafgarh Delhi 💯Call Us 🔝8264348440🔝Call Girls in Najafgarh Delhi 💯Call Us 🔝8264348440🔝
Call Girls in Najafgarh Delhi 💯Call Us 🔝8264348440🔝soniya singh
 
定制(UofT毕业证书)加拿大多伦多大学毕业证成绩单原版一比一
定制(UofT毕业证书)加拿大多伦多大学毕业证成绩单原版一比一定制(UofT毕业证书)加拿大多伦多大学毕业证成绩单原版一比一
定制(UofT毕业证书)加拿大多伦多大学毕业证成绩单原版一比一lvtagr7
 
Call Girls in Faridabad 9000000000 Faridabad Escorts Service
Call Girls in Faridabad 9000000000 Faridabad Escorts ServiceCall Girls in Faridabad 9000000000 Faridabad Escorts Service
Call Girls in Faridabad 9000000000 Faridabad Escorts ServiceTina Ji
 

Último (20)

Call Girls Somajiguda Sarani 7001305949 all area service COD available Any Time
Call Girls Somajiguda Sarani 7001305949 all area service COD available Any TimeCall Girls Somajiguda Sarani 7001305949 all area service COD available Any Time
Call Girls Somajiguda Sarani 7001305949 all area service COD available Any Time
 
QUIZ BOLLYWOOD ( weekly quiz ) - SJU quizzers
QUIZ BOLLYWOOD ( weekly quiz ) - SJU quizzersQUIZ BOLLYWOOD ( weekly quiz ) - SJU quizzers
QUIZ BOLLYWOOD ( weekly quiz ) - SJU quizzers
 
8377087607 Full Enjoy @24/7 Call Girls in Patel Nagar Delhi NCR
8377087607 Full Enjoy @24/7 Call Girls in Patel Nagar Delhi NCR8377087607 Full Enjoy @24/7 Call Girls in Patel Nagar Delhi NCR
8377087607 Full Enjoy @24/7 Call Girls in Patel Nagar Delhi NCR
 
High Profile Call Girls Sodepur - 8250192130 Escorts Service with Real Photos...
High Profile Call Girls Sodepur - 8250192130 Escorts Service with Real Photos...High Profile Call Girls Sodepur - 8250192130 Escorts Service with Real Photos...
High Profile Call Girls Sodepur - 8250192130 Escorts Service with Real Photos...
 
Call Girls Near Taurus Sarovar Portico Hotel New Delhi 9873777170
Call Girls Near Taurus Sarovar Portico Hotel New Delhi 9873777170Call Girls Near Taurus Sarovar Portico Hotel New Delhi 9873777170
Call Girls Near Taurus Sarovar Portico Hotel New Delhi 9873777170
 
Fun Call Girls In Goa 7028418221 Escort Service In Morjim Beach Call Girl
Fun Call Girls In Goa 7028418221 Escort Service In Morjim Beach Call GirlFun Call Girls In Goa 7028418221 Escort Service In Morjim Beach Call Girl
Fun Call Girls In Goa 7028418221 Escort Service In Morjim Beach Call Girl
 
VIP Call Girls In Goa 7028418221 Call Girls In Baga Beach Escorts Service
VIP Call Girls In Goa 7028418221 Call Girls In Baga Beach Escorts ServiceVIP Call Girls In Goa 7028418221 Call Girls In Baga Beach Escorts Service
VIP Call Girls In Goa 7028418221 Call Girls In Baga Beach Escorts Service
 
Vip Udaipur Call Girls 9602870969 Dabok Airport Udaipur Escorts Service
Vip Udaipur Call Girls 9602870969 Dabok Airport Udaipur Escorts ServiceVip Udaipur Call Girls 9602870969 Dabok Airport Udaipur Escorts Service
Vip Udaipur Call Girls 9602870969 Dabok Airport Udaipur Escorts Service
 
Housewife Call Girls Sonagachi - 8250192130 Booking and charges genuine rate ...
Housewife Call Girls Sonagachi - 8250192130 Booking and charges genuine rate ...Housewife Call Girls Sonagachi - 8250192130 Booking and charges genuine rate ...
Housewife Call Girls Sonagachi - 8250192130 Booking and charges genuine rate ...
 
Kolkata Call Girl Howrah 👉 8250192130 ❣️💯 Available With Room 24×7
Kolkata Call Girl Howrah 👉 8250192130 ❣️💯 Available With Room 24×7Kolkata Call Girl Howrah 👉 8250192130 ❣️💯 Available With Room 24×7
Kolkata Call Girl Howrah 👉 8250192130 ❣️💯 Available With Room 24×7
 
Air-Hostess Call Girls Shobhabazar | 8250192130 At Low Cost Cash Payment Booking
Air-Hostess Call Girls Shobhabazar | 8250192130 At Low Cost Cash Payment BookingAir-Hostess Call Girls Shobhabazar | 8250192130 At Low Cost Cash Payment Booking
Air-Hostess Call Girls Shobhabazar | 8250192130 At Low Cost Cash Payment Booking
 
Call Girls Koti 7001305949 all area service COD available Any Time
Call Girls Koti 7001305949 all area service COD available Any TimeCall Girls Koti 7001305949 all area service COD available Any Time
Call Girls Koti 7001305949 all area service COD available Any Time
 
Hifi Laxmi Nagar Call Girls Service WhatsApp -> 9999965857 Available 24x7 ^ D...
Hifi Laxmi Nagar Call Girls Service WhatsApp -> 9999965857 Available 24x7 ^ D...Hifi Laxmi Nagar Call Girls Service WhatsApp -> 9999965857 Available 24x7 ^ D...
Hifi Laxmi Nagar Call Girls Service WhatsApp -> 9999965857 Available 24x7 ^ D...
 
Hot Call Girls In Goa 7028418221 Call Girls In Vagator Beach EsCoRtS
Hot Call Girls In Goa 7028418221 Call Girls In Vagator Beach EsCoRtSHot Call Girls In Goa 7028418221 Call Girls In Vagator Beach EsCoRtS
Hot Call Girls In Goa 7028418221 Call Girls In Vagator Beach EsCoRtS
 
ViP Call Girls In Udaipur 9602870969 Gulab Bagh Escorts SeRvIcE
ViP Call Girls In Udaipur 9602870969 Gulab Bagh Escorts SeRvIcEViP Call Girls In Udaipur 9602870969 Gulab Bagh Escorts SeRvIcE
ViP Call Girls In Udaipur 9602870969 Gulab Bagh Escorts SeRvIcE
 
Cash Payment Contact:- 7028418221 Goa Call Girls Service North Goa Escorts
Cash Payment Contact:- 7028418221 Goa Call Girls Service North Goa EscortsCash Payment Contact:- 7028418221 Goa Call Girls Service North Goa Escorts
Cash Payment Contact:- 7028418221 Goa Call Girls Service North Goa Escorts
 
Call Girls Ellis Bridge 7397865700 Independent Call Girls
Call Girls Ellis Bridge 7397865700 Independent Call GirlsCall Girls Ellis Bridge 7397865700 Independent Call Girls
Call Girls Ellis Bridge 7397865700 Independent Call Girls
 
Call Girls in Najafgarh Delhi 💯Call Us 🔝8264348440🔝
Call Girls in Najafgarh Delhi 💯Call Us 🔝8264348440🔝Call Girls in Najafgarh Delhi 💯Call Us 🔝8264348440🔝
Call Girls in Najafgarh Delhi 💯Call Us 🔝8264348440🔝
 
定制(UofT毕业证书)加拿大多伦多大学毕业证成绩单原版一比一
定制(UofT毕业证书)加拿大多伦多大学毕业证成绩单原版一比一定制(UofT毕业证书)加拿大多伦多大学毕业证成绩单原版一比一
定制(UofT毕业证书)加拿大多伦多大学毕业证成绩单原版一比一
 
Call Girls in Faridabad 9000000000 Faridabad Escorts Service
Call Girls in Faridabad 9000000000 Faridabad Escorts ServiceCall Girls in Faridabad 9000000000 Faridabad Escorts Service
Call Girls in Faridabad 9000000000 Faridabad Escorts Service
 

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