SlideShare ist ein Scribd-Unternehmen logo
1 von 70
Downloaden Sie, um offline zu lesen
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 ïŹrst.
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

Weitere Àhnliche Inhalte

Was ist angesagt?

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
 
Rails is not just Ruby
Rails is not just RubyRails is not just Ruby
Rails is not just RubyMarco Otte-Witte
 
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
 
Ember - introduction
Ember - introductionEmber - introduction
Ember - introductionHarikrishnan C
 
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
 

Was ist angesagt? (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
 

Andere mochten auch

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
 
The Immobile Web
The Immobile WebThe Immobile Web
The Immobile WebJason Grigsby
 
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
 
Masa Israel Programs Overview
Masa Israel Programs OverviewMasa Israel Programs Overview
Masa Israel Programs OverviewMasa Israel Journey
 
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
 

Andere mochten auch (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
 

Ähnlich wie Complex Architectures in Ember

Knockout.js presentation
Knockout.js presentationKnockout.js presentation
Knockout.js presentationScott Messinger
 
Backbone
BackboneBackbone
BackboneYnon Perek
 
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
 
Angular Workshop_Sarajevo2
Angular Workshop_Sarajevo2Angular Workshop_Sarajevo2
Angular Workshop_Sarajevo2Christoffer Noring
 
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
 
DrupalCon jQuery
DrupalCon jQueryDrupalCon jQuery
DrupalCon jQueryNathan 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 Applicaitonsgarbles
 
AppForum 2014 Boost Hybrid App Performance
AppForum 2014 Boost Hybrid App PerformanceAppForum 2014 Boost Hybrid App Performance
AppForum 2014 Boost Hybrid App Performancerobgalvinjr
 
Modern Web Developement
Modern Web DevelopementModern Web Developement
Modern Web Developementpeychevi
 
Introductionandgreetings
IntroductionandgreetingsIntroductionandgreetings
IntroductionandgreetingsPozz ZaRat
 

Ähnlich wie 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
 

Mehr von 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
 
Attribute actions
Attribute actionsAttribute actions
Attribute actionsMatthew 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
 

Mehr von 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
 

KĂŒrzlich hochgeladen

CHEAP Call Girls in Malviya Nagar, (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in  Malviya Nagar, (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICECHEAP Call Girls in  Malviya Nagar, (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Malviya Nagar, (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE9953056974 Low Rate Call Girls In Saket, Delhi NCR
 
Verified Call Girls Esplanade - [ Cash on Delivery ] Contact 8250192130 Escor...
Verified Call Girls Esplanade - [ Cash on Delivery ] Contact 8250192130 Escor...Verified Call Girls Esplanade - [ Cash on Delivery ] Contact 8250192130 Escor...
Verified Call Girls Esplanade - [ Cash on Delivery ] Contact 8250192130 Escor...anamikaraghav4
 
↑Top Model (Kolkata) Call Girls Howrah ⟟ 8250192130 ⟟ High Class Call Girl In...
↑Top Model (Kolkata) Call Girls Howrah ⟟ 8250192130 ⟟ High Class Call Girl In...↑Top Model (Kolkata) Call Girls Howrah ⟟ 8250192130 ⟟ High Class Call Girl In...
↑Top Model (Kolkata) Call Girls Howrah ⟟ 8250192130 ⟟ High Class Call Girl In...noor ahmed
 
Nayabad Call Girls ✔ 8005736733 ✔ Hot Model With Sexy Bhabi Ready For Sex At ...
Nayabad Call Girls ✔ 8005736733 ✔ Hot Model With Sexy Bhabi Ready For Sex At ...Nayabad Call Girls ✔ 8005736733 ✔ Hot Model With Sexy Bhabi Ready For Sex At ...
Nayabad Call Girls ✔ 8005736733 ✔ Hot Model With Sexy Bhabi Ready For Sex At ...aamir
 
Call Girls In Goa 9316020077 Goa Call Girl By Indian Call Girls Goa
Call Girls In Goa  9316020077 Goa  Call Girl By Indian Call Girls GoaCall Girls In Goa  9316020077 Goa  Call Girl By Indian Call Girls Goa
Call Girls In Goa 9316020077 Goa Call Girl By Indian Call Girls Goasexy call girls service in goa
 
(Dipika) Call Girls in Bangur ! 8250192130 â‚č2999 Only and Free Hotel Delivery...
(Dipika) Call Girls in Bangur ! 8250192130 â‚č2999 Only and Free Hotel Delivery...(Dipika) Call Girls in Bangur ! 8250192130 â‚č2999 Only and Free Hotel Delivery...
(Dipika) Call Girls in Bangur ! 8250192130 â‚č2999 Only and Free Hotel Delivery...Riya Pathan
 
Karnal Call Girls 8860008073 Dyal Singh Colony Call Girls Service in Karnal E...
Karnal Call Girls 8860008073 Dyal Singh Colony Call Girls Service in Karnal E...Karnal Call Girls 8860008073 Dyal Singh Colony Call Girls Service in Karnal E...
Karnal Call Girls 8860008073 Dyal Singh Colony Call Girls Service in Karnal E...Apsara Of India
 
2k Shot Call girls Laxmi Nagar Delhi 9205541914
2k Shot Call girls Laxmi Nagar Delhi 92055419142k Shot Call girls Laxmi Nagar Delhi 9205541914
2k Shot Call girls Laxmi Nagar Delhi 9205541914Delhi Call girls
 
👙 Kolkata Call Girls Sonagachi đŸ’«đŸ’«7001035870 Model escorts Service
👙  Kolkata Call Girls Sonagachi đŸ’«đŸ’«7001035870 Model escorts Service👙  Kolkata Call Girls Sonagachi đŸ’«đŸ’«7001035870 Model escorts Service
👙 Kolkata Call Girls Sonagachi đŸ’«đŸ’«7001035870 Model escorts Serviceanamikaraghav4
 
Russian Call Girl South End Park - Call 8250192130 Rs-3500 with A/C Room Cash...
Russian Call Girl South End Park - Call 8250192130 Rs-3500 with A/C Room Cash...Russian Call Girl South End Park - Call 8250192130 Rs-3500 with A/C Room Cash...
Russian Call Girl South End Park - Call 8250192130 Rs-3500 with A/C Room Cash...anamikaraghav4
 
Independent Hatiara Escorts ✔ 8250192130 ✔ Full Night With Room Online Bookin...
Independent Hatiara Escorts ✔ 8250192130 ✔ Full Night With Room Online Bookin...Independent Hatiara Escorts ✔ 8250192130 ✔ Full Night With Room Online Bookin...
Independent Hatiara Escorts ✔ 8250192130 ✔ Full Night With Room Online Bookin...Riya Pathan
 
↑Top Model (Kolkata) Call Girls Rajpur ⟟ 8250192130 ⟟ High Class Call Girl In...
↑Top Model (Kolkata) Call Girls Rajpur ⟟ 8250192130 ⟟ High Class Call Girl In...↑Top Model (Kolkata) Call Girls Rajpur ⟟ 8250192130 ⟟ High Class Call Girl In...
↑Top Model (Kolkata) Call Girls Rajpur ⟟ 8250192130 ⟟ High Class Call Girl In...noor ahmed
 
VIP Call Girls Darjeeling Aaradhya 8250192130 Independent Escort Service Darj...
VIP Call Girls Darjeeling Aaradhya 8250192130 Independent Escort Service Darj...VIP Call Girls Darjeeling Aaradhya 8250192130 Independent Escort Service Darj...
VIP Call Girls Darjeeling Aaradhya 8250192130 Independent Escort Service Darj...Neha Kaur
 
Book Call Girls in Panchpota - 8250192130 | 24x7 Service Available Near Me
Book Call Girls in Panchpota - 8250192130 | 24x7 Service Available Near MeBook Call Girls in Panchpota - 8250192130 | 24x7 Service Available Near Me
Book Call Girls in Panchpota - 8250192130 | 24x7 Service Available Near Meanamikaraghav4
 
Low Rate Call Girls Gulbarga Anika 8250192130 Independent Escort Service Gulb...
Low Rate Call Girls Gulbarga Anika 8250192130 Independent Escort Service Gulb...Low Rate Call Girls Gulbarga Anika 8250192130 Independent Escort Service Gulb...
Low Rate Call Girls Gulbarga Anika 8250192130 Independent Escort Service Gulb...Riya Pathan
 
Call Girl Nagpur Roshni Call 7001035870 Meet With Nagpur Escorts
Call Girl Nagpur Roshni Call 7001035870 Meet With Nagpur EscortsCall Girl Nagpur Roshni Call 7001035870 Meet With Nagpur Escorts
Call Girl Nagpur Roshni Call 7001035870 Meet With Nagpur EscortsCall Girls in Nagpur High Profile
 
VIP Call Girls Service Banjara Hills Hyderabad Call +91-8250192130
VIP Call Girls Service Banjara Hills Hyderabad Call +91-8250192130VIP Call Girls Service Banjara Hills Hyderabad Call +91-8250192130
VIP Call Girls Service Banjara Hills Hyderabad Call +91-8250192130Suhani Kapoor
 
Beautiful 😋 Call girls in Lahore 03210033448
Beautiful 😋 Call girls in Lahore 03210033448Beautiful 😋 Call girls in Lahore 03210033448
Beautiful 😋 Call girls in Lahore 03210033448ont65320
 
Desi Bhabhi Call Girls In Goa 💃 730 02 72 001💃desi Bhabhi Escort Goa
Desi Bhabhi Call Girls  In Goa  💃 730 02 72 001💃desi Bhabhi Escort GoaDesi Bhabhi Call Girls  In Goa  💃 730 02 72 001💃desi Bhabhi Escort Goa
Desi Bhabhi Call Girls In Goa 💃 730 02 72 001💃desi Bhabhi Escort Goarussian goa call girl and escorts service
 

KĂŒrzlich hochgeladen (20)

CHEAP Call Girls in Malviya Nagar, (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in  Malviya Nagar, (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICECHEAP Call Girls in  Malviya Nagar, (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Malviya Nagar, (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
 
Verified Call Girls Esplanade - [ Cash on Delivery ] Contact 8250192130 Escor...
Verified Call Girls Esplanade - [ Cash on Delivery ] Contact 8250192130 Escor...Verified Call Girls Esplanade - [ Cash on Delivery ] Contact 8250192130 Escor...
Verified Call Girls Esplanade - [ Cash on Delivery ] Contact 8250192130 Escor...
 
↑Top Model (Kolkata) Call Girls Howrah ⟟ 8250192130 ⟟ High Class Call Girl In...
↑Top Model (Kolkata) Call Girls Howrah ⟟ 8250192130 ⟟ High Class Call Girl In...↑Top Model (Kolkata) Call Girls Howrah ⟟ 8250192130 ⟟ High Class Call Girl In...
↑Top Model (Kolkata) Call Girls Howrah ⟟ 8250192130 ⟟ High Class Call Girl In...
 
Nayabad Call Girls ✔ 8005736733 ✔ Hot Model With Sexy Bhabi Ready For Sex At ...
Nayabad Call Girls ✔ 8005736733 ✔ Hot Model With Sexy Bhabi Ready For Sex At ...Nayabad Call Girls ✔ 8005736733 ✔ Hot Model With Sexy Bhabi Ready For Sex At ...
Nayabad Call Girls ✔ 8005736733 ✔ Hot Model With Sexy Bhabi Ready For Sex At ...
 
Call Girls South Avenue Delhi WhatsApp Number 9711199171
Call Girls South Avenue Delhi WhatsApp Number 9711199171Call Girls South Avenue Delhi WhatsApp Number 9711199171
Call Girls South Avenue Delhi WhatsApp Number 9711199171
 
Call Girls In Goa 9316020077 Goa Call Girl By Indian Call Girls Goa
Call Girls In Goa  9316020077 Goa  Call Girl By Indian Call Girls GoaCall Girls In Goa  9316020077 Goa  Call Girl By Indian Call Girls Goa
Call Girls In Goa 9316020077 Goa Call Girl By Indian Call Girls Goa
 
(Dipika) Call Girls in Bangur ! 8250192130 â‚č2999 Only and Free Hotel Delivery...
(Dipika) Call Girls in Bangur ! 8250192130 â‚č2999 Only and Free Hotel Delivery...(Dipika) Call Girls in Bangur ! 8250192130 â‚č2999 Only and Free Hotel Delivery...
(Dipika) Call Girls in Bangur ! 8250192130 â‚č2999 Only and Free Hotel Delivery...
 
Karnal Call Girls 8860008073 Dyal Singh Colony Call Girls Service in Karnal E...
Karnal Call Girls 8860008073 Dyal Singh Colony Call Girls Service in Karnal E...Karnal Call Girls 8860008073 Dyal Singh Colony Call Girls Service in Karnal E...
Karnal Call Girls 8860008073 Dyal Singh Colony Call Girls Service in Karnal E...
 
2k Shot Call girls Laxmi Nagar Delhi 9205541914
2k Shot Call girls Laxmi Nagar Delhi 92055419142k Shot Call girls Laxmi Nagar Delhi 9205541914
2k Shot Call girls Laxmi Nagar Delhi 9205541914
 
👙 Kolkata Call Girls Sonagachi đŸ’«đŸ’«7001035870 Model escorts Service
👙  Kolkata Call Girls Sonagachi đŸ’«đŸ’«7001035870 Model escorts Service👙  Kolkata Call Girls Sonagachi đŸ’«đŸ’«7001035870 Model escorts Service
👙 Kolkata Call Girls Sonagachi đŸ’«đŸ’«7001035870 Model escorts Service
 
Russian Call Girl South End Park - Call 8250192130 Rs-3500 with A/C Room Cash...
Russian Call Girl South End Park - Call 8250192130 Rs-3500 with A/C Room Cash...Russian Call Girl South End Park - Call 8250192130 Rs-3500 with A/C Room Cash...
Russian Call Girl South End Park - Call 8250192130 Rs-3500 with A/C Room Cash...
 
Independent Hatiara Escorts ✔ 8250192130 ✔ Full Night With Room Online Bookin...
Independent Hatiara Escorts ✔ 8250192130 ✔ Full Night With Room Online Bookin...Independent Hatiara Escorts ✔ 8250192130 ✔ Full Night With Room Online Bookin...
Independent Hatiara Escorts ✔ 8250192130 ✔ Full Night With Room Online Bookin...
 
↑Top Model (Kolkata) Call Girls Rajpur ⟟ 8250192130 ⟟ High Class Call Girl In...
↑Top Model (Kolkata) Call Girls Rajpur ⟟ 8250192130 ⟟ High Class Call Girl In...↑Top Model (Kolkata) Call Girls Rajpur ⟟ 8250192130 ⟟ High Class Call Girl In...
↑Top Model (Kolkata) Call Girls Rajpur ⟟ 8250192130 ⟟ High Class Call Girl In...
 
VIP Call Girls Darjeeling Aaradhya 8250192130 Independent Escort Service Darj...
VIP Call Girls Darjeeling Aaradhya 8250192130 Independent Escort Service Darj...VIP Call Girls Darjeeling Aaradhya 8250192130 Independent Escort Service Darj...
VIP Call Girls Darjeeling Aaradhya 8250192130 Independent Escort Service Darj...
 
Book Call Girls in Panchpota - 8250192130 | 24x7 Service Available Near Me
Book Call Girls in Panchpota - 8250192130 | 24x7 Service Available Near MeBook Call Girls in Panchpota - 8250192130 | 24x7 Service Available Near Me
Book Call Girls in Panchpota - 8250192130 | 24x7 Service Available Near Me
 
Low Rate Call Girls Gulbarga Anika 8250192130 Independent Escort Service Gulb...
Low Rate Call Girls Gulbarga Anika 8250192130 Independent Escort Service Gulb...Low Rate Call Girls Gulbarga Anika 8250192130 Independent Escort Service Gulb...
Low Rate Call Girls Gulbarga Anika 8250192130 Independent Escort Service Gulb...
 
Call Girl Nagpur Roshni Call 7001035870 Meet With Nagpur Escorts
Call Girl Nagpur Roshni Call 7001035870 Meet With Nagpur EscortsCall Girl Nagpur Roshni Call 7001035870 Meet With Nagpur Escorts
Call Girl Nagpur Roshni Call 7001035870 Meet With Nagpur Escorts
 
VIP Call Girls Service Banjara Hills Hyderabad Call +91-8250192130
VIP Call Girls Service Banjara Hills Hyderabad Call +91-8250192130VIP Call Girls Service Banjara Hills Hyderabad Call +91-8250192130
VIP Call Girls Service Banjara Hills Hyderabad Call +91-8250192130
 
Beautiful 😋 Call girls in Lahore 03210033448
Beautiful 😋 Call girls in Lahore 03210033448Beautiful 😋 Call girls in Lahore 03210033448
Beautiful 😋 Call girls in Lahore 03210033448
 
Desi Bhabhi Call Girls In Goa 💃 730 02 72 001💃desi Bhabhi Escort Goa
Desi Bhabhi Call Girls  In Goa  💃 730 02 72 001💃desi Bhabhi Escort GoaDesi Bhabhi Call Girls  In Goa  💃 730 02 72 001💃desi Bhabhi Escort Goa
Desi Bhabhi Call Girls In Goa 💃 730 02 72 001💃desi Bhabhi Escort Goa
 

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 ïŹrst. 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