architecture: ember.js and angularjs
DESCRIPTION
An introduction to the different architectures of Ember and Angular, two leading JavaScript singlepage / MVC frameworks. This presentation was given to the Los Angeles RailsBridge "Architecture" meeting on October 25, 2013.TRANSCRIPT
Ember.js and AngularJSTwo Architectures Compared
Evan Dorn and Hannah Howard
Logical Reality Design
http://[email protected]
@idahoev
[email protected]@techgirlwonder
Tuesday, November 19, 13
How do I web application?
Tuesday, November 19, 13
Simple apps can usesimple tools.
Tuesday, November 19, 13
BIG APPS NEED
ARCHITECTURE
Tuesday, November 19, 13
BIG APPS NEED
ARCHITECTURE•Keep it organized!
Tuesday, November 19, 13
BIG APPS NEED
ARCHITECTURE•Keep it organized!
•Modularize your code!
Tuesday, November 19, 13
BIG APPS NEED
ARCHITECTURE•Keep it organized!
•Modularize your code!
•Separate concerns!
Tuesday, November 19, 13
BIG APPS NEED
ARCHITECTURE•Keep it organized!
•Modularize your code!
•Separate concerns!
•Establish conventions for smooth teamwork!
Tuesday, November 19, 13
BIG APPS NEED
ARCHITECTURE•Keep it organized!
•Modularize your code!
•Separate concerns!
•Establish conventions for smooth teamwork!
•Keep it testable!
Tuesday, November 19, 13
Most tools use some variant of
MVC“Model, View, Controller"
Tuesday, November 19, 13
WARNING!
Tuesday, November 19, 13
“MVC” is used in many different ways!
Tuesday, November 19, 13
MVC (ROUGHLY)View(UI)
Model(data)
Controller(interface)
Tuesday, November 19, 13
BUT SOMETIMES...
View Model
Controller
Tuesday, November 19, 13
OTHER TIMES...
View Model
Controller
Presenter
Tuesday, November 19, 13
OR EVEN...
View Model
Controller
Presenter
Tuesday, November 19, 13
The Web App Challenge
Tuesday, November 19, 13
Server
CLASSIC RAILS APP
View Model
Controller
Browser
DOM UX
“The Page”HTTP
Markup
Request
Tuesday, November 19, 13
THE PROBLEMS:
Tuesday, November 19, 13
THE PROBLEMS:•All possible user actions must be precomputed
Tuesday, November 19, 13
THE PROBLEMS:•All possible user actions must be precomputed
•... and embedded into the HTML
Tuesday, November 19, 13
THE PROBLEMS:•All possible user actions must be precomputed
•... and embedded into the HTML
•Reloading the whole page every request
Tuesday, November 19, 13
THE PROBLEMS:•All possible user actions must be precomputed
•... and embedded into the HTML
•Reloading the whole page every request
•Some actions not possible without browser interactivity
Tuesday, November 19, 13
HOW DO WE ARCHITECT
A BROWSER APP?
Tuesday, November 19, 13
ServerMostly persistence
JS SINGLE-PAGE APP
ModelController
BrowserApp for user interaction
View Model
Controller
Tuesday, November 19, 13
ServerPersistence Only!
JS SINGLE-PAGE APP
Model
BrowserApp for user interaction
View Model
Controller
Tuesday, November 19, 13
FOR MORE INFO
Tuesday, November 19, 13
FOR MORE INFO
Google Yehuda Katz’ Excellent Presentation:
Tuesday, November 19, 13
FOR MORE INFO
Google Yehuda Katz’ Excellent Presentation:
“A Tale of Two MVC’s”
Tuesday, November 19, 13
FOR MORE INFO
Google Yehuda Katz’ Excellent Presentation:
“A Tale of Two MVC’s”From GoGaRuCo 2013
Tuesday, November 19, 13
FOR MORE INFO
Google Yehuda Katz’ Excellent Presentation:
“A Tale of Two MVC’s”From GoGaRuCo 2013
Tuesday, November 19, 13
EMBER.JS & ANGULARJS
BOTH USE “MVC” THINKING
Tuesday, November 19, 13
BUT WITH DIFFERENT PHILOSOPHIES...
Tuesday, November 19, 13
BUT WITH DIFFERENT PHILOSOPHIES...
..LEADING TO DIFFERENT
ARCHITECTURESTuesday, November 19, 13
BROWSER APP?
Tuesday, November 19, 13
BROWSER APP?
Ember.js Sees:
Tuesday, November 19, 13
BROWSER APP?
Ember.js Sees:
Browser APP
Tuesday, November 19, 13
BROWSER APP?
Ember.js Sees:
Browser APP
AngularJS Sees:
Tuesday, November 19, 13
BROWSER APP?
Ember.js Sees:
Browser APP
AngularJS Sees:
Browser App
Tuesday, November 19, 13
PHILOSOPHY: EMBER
Tuesday, November 19, 13
PHILOSOPHY: EMBER
•Take known techniques for building apps
Tuesday, November 19, 13
PHILOSOPHY: EMBER
•Take known techniques for building apps
•... concepts from Rails
Tuesday, November 19, 13
PHILOSOPHY: EMBER
•Take known techniques for building apps
•... concepts from Rails
•... concepts from Cocoa
Tuesday, November 19, 13
PHILOSOPHY: EMBER
•Take known techniques for building apps
•... concepts from Rails
•... concepts from Cocoa
•Apply them to the browser
Tuesday, November 19, 13
PHILOSOPHY: ANGULAR
Tuesday, November 19, 13
PHILOSOPHY: ANGULAR•Start from the browser - HTML and CSS
Tuesday, November 19, 13
PHILOSOPHY: ANGULAR•Start from the browser - HTML and CSS
•Extend those concepts to app creation
Tuesday, November 19, 13
PHILOSOPHY: ANGULAR•Start from the browser - HTML and CSS
•Extend those concepts to app creation
•Angular asks... What would markup look like, if it were designed for building apps instead of just pages?
Tuesday, November 19, 13
SHARED ASPECTS:
Tuesday, November 19, 13
SHARED ASPECTS:•Single point of truth - the Model
Tuesday, November 19, 13
SHARED ASPECTS:•Single point of truth - the Model
•MVC thinking
Tuesday, November 19, 13
SHARED ASPECTS:•Single point of truth - the Model
•MVC thinking
•Routes connect user actions to controllers
Tuesday, November 19, 13
EMBER PRIORITIES
Tuesday, November 19, 13
EMBER PRIORITIES•Unified interface to data
Tuesday, November 19, 13
EMBER PRIORITIES•Unified interface to data
•Convention of structure
Tuesday, November 19, 13
EMBER PRIORITIES•Unified interface to data
•Convention of structure
•Sharing Of URLs
Tuesday, November 19, 13
EMBER PRIORITIES•Unified interface to data
•Convention of structure
•Sharing Of URLs
•UI Design
Tuesday, November 19, 13
ANGULAR PRIORITIES
Tuesday, November 19, 13
ANGULAR PRIORITIES•Web-UX driven thinking
Tuesday, November 19, 13
ANGULAR PRIORITIES•Web-UX driven thinking
•Isolatable / testable code
Tuesday, November 19, 13
ANGULAR PRIORITIES•Web-UX driven thinking
•Isolatable / testable code
•Add app features by augmenting the DOM
Tuesday, November 19, 13
SYN-NAPS #1
Tuesday, November 19, 13
SYN-NAPS #1•Attentional focus is best < 15 minutes
Tuesday, November 19, 13
SYN-NAPS #1•Attentional focus is best < 15 minutes
•Best to take breaks to let the synapses recover
Tuesday, November 19, 13
SYN-NAPS #1•Attentional focus is best < 15 minutes
•Best to take breaks to let the synapses recover
•So let’s do a little exercise to review
Tuesday, November 19, 13
DIFFERENT JOBSNEED DIFFERENT
ARCHITECTURES
Tuesday, November 19, 13
GRAB A NEIGHBOR NEXT TO YOU
Tuesday, November 19, 13
DISCUSS WITH THEM:
Tuesday, November 19, 13
DISCUSS WITH THEM:
1. An app that’s too small to need MVC
Tuesday, November 19, 13
DISCUSS WITH THEM:
1. An app that’s too small to need MVC
2. A small app that grew till it needed MVC
Tuesday, November 19, 13
DISCUSS WITH THEM:
1. An app that’s too small to need MVC
2. A small app that grew till it needed MVC
3. Any platform is fine!
Tuesday, November 19, 13
SYN-NAPS #1
Tuesday, November 19, 13
SYN-NAPS #1
3 minutes...
Tuesday, November 19, 13
SYN-NAPS #1
3 minutes... GO!Tuesday, November 19, 13
SYN-NAPS #1
Tuesday, November 19, 13
SYN-NAPS #1
3 minutes...
Tuesday, November 19, 13
SYN-NAPS #1
3 minutes... STOP!Tuesday, November 19, 13
EMBER ARCHITECTURE1:START
Tuesday, November 19, 13
EMBER ARCHITECTURE1:START
Ember starts with the URL/Route
Tuesday, November 19, 13
EMBER ARCHITECTURE1:START
Ember starts with the URL/Route
Loads Model
Tuesday, November 19, 13
EMBER ARCHITECTURE1:START
Ember starts with the URL/Route
Loads Model
Renders Template
Tuesday, November 19, 13
EMBER ARCHITECTURE1:START
Ember starts with the URL/Route
Loads Model
Renders Template
Adds Template To DOM
Tuesday, November 19, 13
EMBER ARCHITECTURE2: RUNTIME
Tuesday, November 19, 13
EMBER ARCHITECTURE2: RUNTIME
Ember Watches for Events
Tuesday, November 19, 13
EMBER ARCHITECTURE2: RUNTIME
Ember Watches for Events
Passes Events To Controller (or bubbles up to Route) to update model
Tuesday, November 19, 13
EMBER ARCHITECTURE2: RUNTIME
Ember Watches for Events
Passes Events To Controller (or bubbles up to Route) to update model
DOM auto-updates
Tuesday, November 19, 13
EMBER ARCHITECTURE3: ROUTER
Tuesday, November 19, 13
EMBER ARCHITECTURE3: ROUTER
•The entry point for everything in Ember is the router
Tuesday, November 19, 13
EMBER ARCHITECTURE3: ROUTER
•The entry point for everything in Ember is the router
•Looks a lot like a routes.rb in Rails
Tuesday, November 19, 13
EMBER ARCHITECTURE3: ROUTER
•The entry point for everything in Ember is the router
•Looks a lot like a routes.rb in Rails
•Different: Fetches the Model for the Controller
Tuesday, November 19, 13
EMBER ARCHITECTURE 4: ROUTER
App.Router.map(function() { // put your routes here});
App.IndexRoute = Ember.Route.extend({ model: function() { return ['red', 'yellow', 'blue']; }});
<script type="text/x-handlebars"><h2>Welcome to Ember.js</h2>{{outlet}}</script>
<script type="text/x-handlebars" data-template-name="index"><ul>{{#each item in model}}<li>{{item}}</li>{{/each}}</ul></script>
Tuesday, November 19, 13
EMBER ARCHITECTURE 4: TEMPLATE
App.Router.map(function() { // put your routes here});
App.IndexRoute = Ember.Route.extend({ model: function() { return ['red', 'yellow', 'blue']; }});
<script type="text/x-handlebars"><h2>Welcome to Ember.js</h2>{{outlet}}</script>
<script type="text/x-handlebars" data-template-name="index"><ul>{{#each item in model}}<li>{{item}}</li>{{/each}}</ul></script>
Tuesday, November 19, 13
EMBER ARCHITECTURE 5:CONTROLLERS
Tuesday, November 19, 13
EMBER ARCHITECTURE 5:CONTROLLERS
•Controllers perform two functions in Ember:
Tuesday, November 19, 13
EMBER ARCHITECTURE 5:CONTROLLERS
•Controllers perform two functions in Ember:
•1. Add presentation to the model
Tuesday, November 19, 13
EMBER ARCHITECTURE 5:CONTROLLERS
•Controllers perform two functions in Ember:
•1. Add presentation to the model
•2. Receive browser events and translate them to semantic events
Tuesday, November 19, 13
EMBER ARCHITECTURE 5: CONTROLLERSApp.ContractController = Ember.ObjectController.extend({ fullName: function() { return this.get(“firstName”) + “ “ + this.get(“lastName”); }.properties(“firstName”, “lastName”)});
<script type="text/x-handlebars" data-template-name=”contact”><div>My full name is: {{fullName}}</div></script>
Tuesday, November 19, 13
EMBER ARCHITECTURE 5: CONTROLLERSApp.ContractController = Ember.ObjectController.extend({ fullName: function() { return this.get(“firstName”) + “ “ + this.get(“lastName”); }.properties(“firstName”, “lastName”)});
<script type="text/x-handlebars" data-template-name=”contact”><div>My full name is: {{fullName}}</div></script>
Tuesday, November 19, 13
EMBER ARCHITECTURE 5: CONTROLLERS
App.TicketsController = Ember.ArrayController.extend({ actions: { addItem: function() { this.pushObject(this.get(“ticket”)); } }});
<script type="text/x-handlebars" data-template-name="tickets"><form {{action "addItem" on="submit"}}>{{input value=ticket}}<button type=submit>Add</button></form></script>
Tuesday, November 19, 13
EMBER ARCHITECTURE 5: CONTROLLERS
App.TicketsController = Ember.ArrayController.extend({ actions: { addItem: function() { this.pushObject(this.get(“ticket”)); } }});
<script type="text/x-handlebars" data-template-name="tickets"><form {{action "addItem" on="submit"}}>{{input value=ticket}}<button type=submit>Add</button></form></script>
Tuesday, November 19, 13
EMBER ARCHITECTURE 6:DATA BINDING
Tuesday, November 19, 13
EMBER ARCHITECTURE 6:DATA BINDING
•Is done with computed properties
Tuesday, November 19, 13
EMBER ARCHITECTURE 6:DATA BINDING
•Is done with computed properties
•Available on Models, Controllers, Data Stores, etc.
Tuesday, November 19, 13
EMBER ARCHITECTURE 6:DATA BINDING
•Is done with computed properties
•Available on Models, Controllers, Data Stores, etc.
•Define a function property and add dependencies to it with .properties()
Tuesday, November 19, 13
EMBER ARCHITECTURE 6: DATA BINDING
App.Ticket = Ember.Object.extend({
name: null, priority: null,
abbreviation: function () { shortName = this.get('name'); return shortName.slice(0,3); }.property('name')
});
Tuesday, November 19, 13
EMBER ARCHITECTURE 6: DATA BINDING
App.Ticket = Ember.Object.extend({
name: null, priority: null,
abbreviation: function () { shortName = this.get('name'); return shortName.slice(0,3); }.property('name')
});
Tuesday, November 19, 13
ANGULAR TIME!
Tuesday, November 19, 13
ANGULAR ARCHITECTURE 1: STARTUP
Tuesday, November 19, 13
ANGULAR ARCHITECTURE 1: STARTUP
Angular reads a marked-up HTML file
Tuesday, November 19, 13
ANGULAR ARCHITECTURE 1: STARTUP
Angular reads a marked-up HTML file
Processes it according to directives (yours and AJS’s)
Tuesday, November 19, 13
ANGULAR ARCHITECTURE 1: STARTUP
Angular reads a marked-up HTML file
Processes it according to directives (yours and AJS’s)
Binds view elements to Model data
Tuesday, November 19, 13
ANGULAR ARCHITECTURE 2: RUNTIME
Tuesday, November 19, 13
ANGULAR ARCHITECTURE 2: RUNTIME
Angular watches for events, and changes to bound entities
Tuesday, November 19, 13
ANGULAR ARCHITECTURE 2: RUNTIME
Angular watches for events, and changes to bound entities
Updates bound pairs, calls watch methods
Tuesday, November 19, 13
ANGULAR ARCHITECTURE 2: RUNTIME
Angular watches for events, and changes to bound entities
Updates bound pairs, calls watch methods
Re-renders the DOM as a result
Tuesday, November 19, 13
ANGULAR ARCHITECTURE 3: $SCOPE
Tuesday, November 19, 13
ANGULAR ARCHITECTURE 3: $SCOPE
•A special JS object that groups all the stuff for the current controller context.
Tuesday, November 19, 13
ANGULAR ARCHITECTURE 3: $SCOPE
•A special JS object that groups all the stuff for the current controller context.
•Has inheritable properties and sub-scopes; a bit magical
Tuesday, November 19, 13
ANGULAR ARCHITECTURE 3: $SCOPE
•A special JS object that groups all the stuff for the current controller context.
•Has inheritable properties and sub-scopes; a bit magical
•Inheritance is determined by controller inheritance.
Tuesday, November 19, 13
ANGULAR ARCHITECTURE 4:MODELS
Tuesday, November 19, 13
ANGULAR ARCHITECTURE 4:MODELS
•A model is any JS object (not function!) assigned as a property on the current $scope.
Tuesday, November 19, 13
ANGULAR ARCHITECTURE 4:MODELS
•A model is any JS object (not function!) assigned as a property on the current $scope.
•No class to extend!
Tuesday, November 19, 13
ANGULAR ARCHITECTURE 4:MODELS
•A model is any JS object (not function!) assigned as a property on the current $scope.
•No class to extend!
•Automatically available to any controller that uses that $scope or a sub-scope.
Tuesday, November 19, 13
ANGULAR ARCHITECTURE 4:MODELS
•A model is any JS object (not function!) assigned as a property on the current $scope.
•No class to extend!
•Automatically available to any controller that uses that $scope or a sub-scope.
•Automatically two-way bound to view elements
Tuesday, November 19, 13
ANGULAR ARCHITECTURE 5: CONTROLLERS
Tuesday, November 19, 13
ANGULAR ARCHITECTURE 5: CONTROLLERS
•A controller is just any JS function that receives and processes on a $scope.
Tuesday, November 19, 13
ANGULAR ARCHITECTURE 5: CONTROLLERS
•A controller is just any JS function that receives and processes on a $scope.
•No class to extend or API to call!
Tuesday, November 19, 13
ANGULAR ARCHITECTURE 5: CONTROLLERS
•A controller is just any JS function that receives and processes on a $scope.
•No class to extend or API to call!
•Which controller is relevant is determined by the markup.
Tuesday, November 19, 13
ANGULAR ARCHITECTURE 5: CONTROLLERS
•A controller is just any JS function that receives and processes on a $scope.
•No class to extend or API to call!
•Which controller is relevant is determined by the markup.
•Inheritance is determined by the markup, too!
Tuesday, November 19, 13
ANGULAR ARCHITECTURE 5: CONTROLLERS
<div ng-controller="SomeController"> {{name}} is {{comment}}! <div ng-controller="InnerController"> {{name}} is {{comment}}! </div></div>
function SomeController($scope, []) { $scope.name = “Evan” $scope.comment = “really cool”}
function InnerController($scope, []) { $scope.comment = “misinformed”}
#outputEvan is really coolEvan is misinformed
Tuesday, November 19, 13
ANGULAR ARCHITECTURE 5: CONTROLLERS
<div ng-controller="SomeController"> {{name}} is {{comment}}! <div ng-controller="InnerController"> {{name}} is {{comment}}! </div></div>
function SomeController($scope, []) { $scope.name = “Evan” $scope.comment = “really cool”}
function InnerController($scope, []) { $scope.comment = “misinformed”}
#outputEvan is really coolEvan is misinformed
Tuesday, November 19, 13
ANGULAR ARCHITECTURE 5: CONTROLLERS
<div ng-controller="SomeController"> {{name}} is {{comment}}! <div ng-controller="InnerController"> {{name}} is {{comment}}! </div></div>
function SomeController($scope, []) { $scope.name = “Evan” $scope.comment = “really cool”}
function InnerController($scope, []) { $scope.comment = “misinformed”}
#outputEvan is really cool!Evan is misinformed!
Tuesday, November 19, 13
ANGULAR ARCHITECTURE 6: DATA BINDING
Tuesday, November 19, 13
ANGULAR ARCHITECTURE 6: DATA BINDING
•Bound DOM elements and model data auto-update each other.
Tuesday, November 19, 13
ANGULAR ARCHITECTURE 6: DATA BINDING
•Bound DOM elements and model data auto-update each other.
•Other code like controller functions that depend on model data are not auto-updated.
Tuesday, November 19, 13
ANGULAR ARCHITECTURE 6: DATA BINDING
•Bound DOM elements and model data auto-update each other.
•Other code like controller functions that depend on model data are not auto-updated.
•but $scope.$watch can create such bindings
Tuesday, November 19, 13
ANGULAR ARCHITECTURE 6: DATA BINDING
<div ng-controller="SomeController"> <input type=‘text’ ng-model=‘name’></input> You typed {{name}}!</div>
function SomeController($scope, []) { # name isn’t even mentioned! # in fact you don’t even need the controller!}
Tuesday, November 19, 13
ANGULAR ARCHITECTURE 6: DATA BINDING
<div ng-controller="SomeController"> <input type=‘text’ ng-model=‘name’></input> You typed {{name}}!</div>
function SomeController($scope, []) { # name isn’t even mentioned! # in fact you don’t even need the controller!}
Tuesday, November 19, 13
ANGULAR ARCHITECTURE 6: DATA BINDING
<div ng-controller="SomeController"> <input type='text' ng-model='name'></input> {{crazy_string}}</div>
function SomeController($scope, []) { $scope.crazy_string = $scope.name + " is crazy!";}
Tuesday, November 19, 13
ANGULAR ARCHITECTURE 6: DATA BINDING
<div ng-controller="SomeController"> <input type='text' ng-model='name'></input> {{crazy_string}}</div>
function SomeController($scope, []) { $scope.crazy_string = $scope.name + " is crazy!";}
Tuesday, November 19, 13
ANGULAR ARCHITECTURE 6: DATA BINDING
<div ng-controller="SomeController"> <input type='text' ng-model='name'></input> {{crazy_string}}</div>
function SomeController($scope, []) { $scope.crazy_string = $scope.name + " is crazy!";}
Tuesday, November 19, 13
ANGULAR ARCHITECTURE 6: DATA BINDING
<div ng-controller="SomeController"> <input type='text' ng-model='name'></input> {{crazy_string}}</div>
function SomeController($scope) { $scope.$watch('name', function(){ $scope.crazy_string = $scope.name + " is crazy!"; })}
Tuesday, November 19, 13
ANGULAR ARCHITECTURE 6: DATA BINDING
<div ng-controller="SomeController"> <input type='text' ng-model='name'></input> {{crazy_string}}</div>
function SomeController($scope) { $scope.$watch('name', function(){ $scope.crazy_string = $scope.name + " is crazy!"; })}
Tuesday, November 19, 13
ANGULAR ARCHITECTURE 6: DATA BINDING
<div ng-controller="SomeController"> <input type='text' ng-model='name'></input> {{crazy_string}}</div>
function SomeController($scope) { $scope.$watch('name', function(){ $scope.crazy_string = $scope.name + " is crazy!"; })}
Tuesday, November 19, 13
ANGULAR ARCHITECTURE 7: DEPENDENCY INJECTION
Tuesday, November 19, 13
ANGULAR ARCHITECTURE 7: DEPENDENCY INJECTION
•All elements get created created with a name (as a string) they are known by.
Tuesday, November 19, 13
ANGULAR ARCHITECTURE 7: DEPENDENCY INJECTION
•All elements get created created with a name (as a string) they are known by.
•Controllers, services, etc.
Tuesday, November 19, 13
ANGULAR ARCHITECTURE 7: DEPENDENCY INJECTION
•All elements get created created with a name (as a string) they are known by.
•Controllers, services, etc.
•All elements get instantiated with a list of names they depend on.
Tuesday, November 19, 13
ANGULAR ARCHITECTURE 7: DEPENDENCY INJECTION
•All elements get created created with a name (as a string) they are known by.
•Controllers, services, etc.
•All elements get instantiated with a list of names they depend on.
•This makes test isolation trivial
Tuesday, November 19, 13
ANGULAR ARCHITECTURE 7: DI var ticketApp = angular.module('ticketApp', []);
ticketApp.factory('TicketList', function(){ # ... });
ticketApp.service(‘BackEndAjaxProvider’, function() { #... })
function TicketsController($scope, TicketList) { #... };
function TicketEditController($scope, [TicketList, BackEndAjaxProvider]) { #... };
Tuesday, November 19, 13
ANGULAR ARCHITECTURE 7: DI var ticketApp = angular.module('ticketApp', []);
ticketApp.factory('TicketList', function(){ # ... });
ticketApp.service('BackEndAjaxProvider', function() { #... })
function TicketsController($scope, TicketList) { #... };
function TicketEditController($scope, [TicketList, BackEndAjaxProvider]) { #... };
Tuesday, November 19, 13
ANGULAR ARCHITECTURE 7: DI var ticketApp = angular.module('ticketApp', []);
ticketApp.factory('TicketList', function(){ # ... });
ticketApp.service(‘BackEndAjaxProvider’, function() { #... })
function TicketsController($scope, TicketList) { #... };
function TicketEditController($scope, TicketList, BackEndAjaxProvider) { #... };
Tuesday, November 19, 13
SYN-NAPS #2
Tuesday, November 19, 13
SYN-NAPS #2QUICK Q&A
Tuesday, November 19, 13
DEMO TIME!(EMBER.JS)
Tuesday, November 19, 13
SYN-NAPS #3
Tuesday, November 19, 13
SYN-NAPS #3PUPPY BREAK!
Tuesday, November 19, 13
Tuesday, November 19, 13
DEMO TIME!(ANGULARJS)
Tuesday, November 19, 13
Thanks!Evan Dorn
and Hannah Howard Logical Reality Design
http://[email protected]
@idahoev
[email protected]@techgirlwonder
Tuesday, November 19, 13