SlideShare a Scribd company logo
8/6/14
THE ART AND
SCIENCE OF
SHIPPING
SINGLE PAGE
APPS WITH
EMBER.JS
UX DEVELOPMENT at frog
@jdcravens
github.com/jessecravens
jessecravens.com
principal web architect | frog Austin
ART & SCIENCE
THE ART &
SCIENCE OF
SHIPPING SINGLE
PAGE APPS WITH
EMBER.JS
2006
2007
!
WHY?
!
!
“YOU HAVE TO KNOW THE PAST TO UNDERSTAND THE PRESENT.”
!
- DR. CARL SAGAN
!
"STUDY THE PAST IF YOU WOULD DEFINE THE FUTURE...."
!
- CONFUCIUS
!
!
!
!
!
TEMPLATES
TRADITIONAL
14
ROUTER
UI
HTML5/CSS3/JavaScript
Web Framework
HTML5/CSS3/JavaScript
Data Services
JSON/XML
Storage
DBs
App Server refresh
refresh
refresh
refresh
refresh
App Server
EARLY SPA
IMPLEMENTATION
15
Container App
HTML5/CSS3
Web Framework
HTML5/CSS3/JavaScript
Data Services
JSON/XML
Render Engine
JavaScript DOM creation
&& String templates
Gadget App
iFrame
initial load
XHR RESPONSE
-JSON MARKUP FORMAT
XHR REQUEST
-JSON ACTION OBJECT
Gadget App
iFrame
Gadget App
iFrame
REQ PARAMs
Iframe Refresh
BACK IN THE DAY … A NAIVE IMPLEMENTATION
!
!
SEGREGATED DESIGN TEAM HANDED OFF PHOTOSHOP COMPS
!
ARCHITECTED SERVER IMPLEMENTATION FIRST
!
LACK OF CONVENTIONS AND DEVELOPER ERGONOMICS
!
YUI MODULE PATTERN
PSEUDO CLASSICAL INHERITANCE
!
JSON MARK UP LANGUAGE
CUSTOM RENDER ENGINE
!
HTML STRINGS AND VARIABLES
DOM CREATION
!
CONTINUATION PASSING AND CALLBACK HELL
!
IFRAMES AND GADGET SPEC
!
!
!
!
!
!
!
App Server
INITIAL LOAD
19
Container App
HTML5/CSS3
Web Framework
HTML5/CSS3/JavaScript
Data Services
JSON/XML
Render Engine
JavaScript DOM creation
&& String templates
Gadget App 1
iFrame
initial load
Gadget App 2
iFrame
Gadget App 3
iFrame
REQ PARAMs
Iframe Refresh
INITIAL LOAD
20
Container App
HTML5/CSS3
Web Framework
HTML5/CSS3/JavaScript
Render Engine
JavaScript DOM creation
&& String templates
initial load
INITIAL LOAD
21
Container App
HTML5/CSS3
Web Framework
HTML5/CSS3/JavaScript
Render Engine
JavaScript DOM creation
&& String templates
initial load
{
"root": “#portal",
"childrenType": "Portal",
"type": "ClientCommandObject",
"children": [{
"childrenType": "TabContainer",
"type": "Portal",
"children": [{
"childrenType": "TabPage",
"type": "TabContainer",
"children": [{
"children": [{
"childrenType": "Gadget",
"type": "Column",
"children": [{
"gadgetType": "MyAccounts",
"gadgetContentType": {
"type": "url"
}
}, {
"gadgetType": "EntOffersMlp",
"gadgetContentType": {
"type": "url"
}
}, {
"gadgetType": "SpendingPlan",
"gadgetContentType": {
"type": "url"
}
}, {
"gadgetType": "ImcoStorefront",
"gadgetContentType": {
"type": "url"
}
},
INITIAL LOAD
22
Container App
HTML5/CSS3
Web Framework
HTML5/CSS3/JavaScript
Render Engine
JavaScript DOM creation
&& String templates
initial load
Main.objects.renderObject(rootEl, configHash);
INITIAL LOAD
23
Container App
HTML5/CSS3
Web Framework
HTML5/CSS3/JavaScript
Render Engine
JavaScript DOM creation
&& String templates
initial load
Main.objects.renderObject = function(root, obj){
this.rootObj = root;
// here you make the call to a function to build out your proper div,
// this will also append it to the root
!
var currentObject = this.constructLayoutObject(this.rootObj, obj);
if(obj.children == null || obj.children.length == 0){
return;
}
else{
// render the branches of the object tree to the root by a recursive call
var i;
for(i=0; i < obj.children.length; i++){
this.renderObject(currentObject, obj.children[i]);
}
}
};
INITIAL LOAD
24
Container App
HTML5/CSS3
Web Framework
HTML5/CSS3/JavaScript
Render Engine
JavaScript DOM creation
&& String templates
initial load
Main.createNode: function(type, id, classNames) {
var node = document.createElement(type);
node.id = id;
if (typeof classNames === 'string' ) {
node.className = classNames;
}
else if (typeof classNames === 'object' ){
var str = classNames.toString();
var classString=str.replace(/,/g,' ');
node.className = classString;
}
return node;
}
INITIAL LOAD
25
Container App
HTML5/CSS3
Web Framework
HTML5/CSS3/JavaScript
Render Engine
JavaScript DOM creation
&& String templates
initial load
!
gadgets.Gadget.prototype.getContent = function(continuation) {
gadgets.callAsyncAndJoin(
[this.getTitleBarContent, this.getUserPrefsDialogContent, this.getMainContent],
function(results) {continuation(results.join(''));},
this);
};
!
gadgets.Gadget.prototype.render = function(chrome) {
if (chrome) {
this.getContent(function(content) {
chrome.innerHTML = content;
});
}
};
!
App Server
LOADED
26
Container App
HTML5/CSS3
Web Framework
HTML5/CSS3/JavaScript
Data Services
JSON/XML
Render Engine
JavaScript DOM creation
&& String templates
Gadget App 1
iFrame
Gadget App 2
iFrame
Gadget App 3
iFrame
REQ PARAMs
Iframe Refresh
POST LOADED
27
Container App
HTML5/CSS3
Web Framework
HTML5/CSS3/JavaScript
Render Engine
JavaScript DOM creation
&& String templates
DRAG N’ DROP EVENT FIRES!
Gadget App 1
iFrame
Gadget App 2
iFrame
Gadget App 3
iFrame
REQ PARAMs
Iframe Refresh
POST LOADED
28
Container App
HTML5/CSS3
Web Framework
HTML5/CSS3/JavaScript
Render Engine
JavaScript DOM creation
&& String templates
Gadget App 1
iFrame
Gadget App 2
iFrame
Gadget App 3
iFrame
REQ PARAMs
Iframe Refresh
x
POST LOADED
29
Container App
HTML5/CSS3
Web Framework
HTML5/CSS3/JavaScript
Render Engine
JavaScript DOM creation
&& String templates
Main.moveGadget = function(obj) {
var serviceUrlConfigObject = obj;
serviceUrlConfigObject.position = (obj.position !== undefined)?obj.position:0;
serviceUrlConfigObject.action = "moveObject";
serviceUrlConfigObject.version = 1;
Main.services.takeAction('handleMoveGadget' , serviceUrlConfigObject);
};
REQ PARAMs
Iframe Refresh
Gadget App 1
iFrame
Gadget App 2
iFrame
Gadget App 3
iFrame
x
POST LOADED
30
Container App
HTML5/CSS3
Web Framework
HTML5/CSS3/JavaScript
Render Engine
JavaScript DOM creation
&& String templates
{
action:”moveGadget",
version:1,
category:category,
order:order
};
XHR REQUEST
-JSON ACTION OBJECT
Gadget App 1
iFrame
Gadget App 2
iFrame
Gadget App 3
iFrame
x
REQ PARAMs
Iframe Refresh
REFRESH
31
Container App
HTML5/CSS3
Web Framework
HTML5/CSS3/JavaScript
Render Engine
JavaScript DOM creation
&& String templates
{
"root": “#portal",
"childrenType": "Portal",
"type": "ClientCommandObject",
"children": [{
"childrenType": "TabContainer",
"type": "Portal",
"children": [{
"childrenType": "TabPage",
"type": "TabContainer",
"children": [{
"children": [{
"childrenType": "Gadget",
"type": "Column",
"children": [{
"gadgetType": "MyAccounts",
"gadgetContentType": {
"type": "url"
}
}, {
"gadgetType": "EntOffersMlp",
"gadgetContentType": {
"type": "url"
}
}, {
"gadgetType": "SpendingPlan",
"gadgetContentType": {
"type": "url"
}
}, {
"gadgetType": "ImcoStorefront",
"gadgetContentType": {
"type": "url"
}
},
XHR RESPONSE
-JSON MARKUP FORMAT
Gadget App 1
iFrame
Gadget App 2
iFrame
Gadget App 3
iFrame
x
REQ PARAMs
Iframe Refresh
App Server
LOADED
32
Container App
HTML5/CSS3
Web Framework
HTML5/CSS3/JavaScript
Data Services
JSON/XML
Render Engine
JavaScript DOM creation
&& String templates
Gadget App 1
iFrame
Gadget App 2
iFrame
Gadget App 3
iFrame
REQ PARAMs
Iframe Refresh
MoveGadget
ChangePage
OpenPanel
AddGadget
DeleteGadget
etc.
WE REALLY NEED RAILS
IN THE BROWSER!
2014
EMBER
37
Views
HTML5/CSS3
Web Framework
HTML5/CSS3/JavaScript Ember.App
JavaScript
Ember Data
JavaScript
ROUTER
JavaScript
Local Storage
JavaScript
initial load
XHR -JSON
WebSocket
TEMPLATES
.hbs
App Server
Data Services
JSON/XML
Models
JavaScript
Controllers
JavaScript
Backburner
JavaScript
Components
JavaScript
present
NxGEN: THE NEW S&P CAPITAL IQ
Working with the S&P labs team we sketched
and visualized 5 key concepts. One of the key
concepts was a way to analyze and view
portfolios through different lenses.
BACK IN THE DAY … A NAIVE IMPLEMENTATION
!
!
SEGREGATED DESIGN TEAM HANDED OFF PHOTOSHOP COMPS
!
ARCHITECTED SERVER IMPLEMENTATION FIRST
!
LACK OF CONVENTIONS AND DEVELOPER ERGONOMICS
!
YUI MODULE PATTERN
PSEUDO CLASSICAL INHERITANCE
!
JSON MARK UP LANGUAGE
CUSTOM RENDER ENGINE
!
HTML STRINGS AND VARIABLES
DOM CREATION
!
CONTINUATION PASSING AND CALLBACK HELL
!
IFRAMES AND GADGET SPEC
!
!
!
!
!
!
!
PRESENT AND FUTURE
!
DESIGN WITH CODE
!
WORK FRONT TO BACK
!
THE EMBER WAY
!
THE EMBER OBJECT MODEL
!
EMBER RUN LOOP AND BACKBURNER
!
JS TEMPLATES W/ HANDLEBARS / HTMLBARS
!
PROMISES AND THE ASYNC ROUTER
!
WEB COMPONENTS
!
!
!
!
!
!
!
DESIGN WITH CODE
SKETCH
ADOBE EDGE REFLOW
WEBFLOW
MACAW
!
SKETCH
ADOBE EDGE REFLOW
WEBFLOW
MACAW
!
CHROME DEV TOOLS
!
WORK FRONT TO BACK
BACK END TEAM
RAPID DEV
57
Early Design: HTML, Diagram Controllers
URL Driven: State Manager and Routes First
Populate the Controllers with Dummy Data
Models w/ Fixtures FixtureAdapter
FRONT END TEAM
Models w/ RESTAdapter
Build Server-Side Routes/Endpoints
Serialization and Formatting JSON
Remote Data Store and DB Sync
!
!
FixtureAdapter RESTAdapter
RAPID DEV
REST ADAPTER
TEMPLATES
FIXTURE ADAPTER
ROUTER
ROUTE HANDLERS
CONTROLLERS
VIEWS/COMPONENTS
MODELS
SERVICES (API DESIGN)
MVC, SPA (Bootstrap Object)
SERVICES (IMPLEMENTATION)
FRONT END DEVELOPMENT
WEB/SERVICES DEVELOPMENT
D
E
P
L
O
Y
C
O
N
C
E
P
T
U
A
L
EMBER DATA
ADAPTERS
!
ADAPTERS
60
App.ApplicationAdapter = DS.FixtureAdapter.extend({
namespace: 'rocknrollcall'
});
!
App.ApplicationAdapter = DS.LSAdapter.extend({
namespace: 'rocknrollcall'
});
!
App.ActivityAdapter = DS.LSAdapter.extend({
namespace: 'rocknrollcall'
});
!
App.ApplicationAdapter = DS.RESTAdapter.extend({
namespace: 'rocknrollcall'
});
NxGEN: THE NEW S&P CAPITAL IQ
API STUBS
!
EMBER APP KIT
63
{
"name": "app-kit",
"namespace": "appkit",
"APIMethod": "stub",
…
ROUTES.JS
64
module.exports = function(server) {
!
// Create an API namespace, so that the root does not
// have to be repeated for each end point.
server.namespace("/api", function() {
!
// Return fixture data for "/api/activities"
server.get("/activities", function(req, res) {
var activities = [ ];
};
res.send(activities);
});
});
};
EMBER APP KIT
65
{
"name": "app-kit",
"namespace": "appkit",
"APIMethod": "stub",
…
!
{
"name": "app-kit",
"namespace": "appkit",
"APIMethod": “proxy”,
"proxyURL": "http://whatever.api:3232",
...
EMBRACE THE EMBER WAY
!
!
FRIENDS OR FOES
ACTIVE GENERATION
!
NAMING CONVENTIONS
!
!
ACTIVE GENERATION
EMBER APPLICATION
70
App = Ember.Application.create({
!
ENV.LOG_MODULE_RESOLVER = true;
ENV.APP.LOG_RESOLVER = true;
ENV.APP.LOG_ACTIVE_GENERATION = true;
ENV.APP.LOG_MODULE_RESOLVER = true;
ENV.APP.LOG_TRANSITIONS = true;
ENV.APP.LOG_TRANSITIONS_INTERNAL = true;
ENV.APP.LOG_VIEW_LOOKUPS = true;
!
});
NAMING CONVENTIONS
CONVENTIONS
NAMING CONVENTIONS
CONVENTIONS
THE EMBER OBJECT MODEL
YUI2
76
YAHOO.namespace(‘App’);
!
App.BaseClass = function(){
method: function(){}
};
!
App.Class = function(){
App.BaseClass.call(this);
};
!
App.Class.inherits(App.BaseClass);
!
App.Class.prototype.method = function(){
!
};
2007
var object = new Base;
!
object.extend({
value: "some data”,
!
method: function() {
alert("Hello World!");
}
!
});
!
object.method();
!
// ==> Hello World!
BASE2
77
2007
EMBER OBJECT
78
App.DefaultPlayer = Em.Object.extend({
!
init: function () {
this.set('imgProfilePrefix', 'default_');
},
!
name: “Steve",
!
imgName: function (imgType) {
return this.get('imgProfilePrefix') +
this.get('name').split(' ').join('_').toLowerCase() +
this.get('imgProfileSuffix') + '.' + imgType;
!
}
!
});
GETTERS AND SETTERS
79
App.DefaultPlayer = Em.Object.extend({
name: “Steve"
});
!
var steve = App.DefaultPlayer.create({});
!
steve.set(‘name’ , ‘Stephen’);
!
steve.get(‘name’); // Stephen
INHERITANCE
80
App.DefaultPlayer = Em.Object.extend({});
!
App.Player = App.DefaultPlayer.extend({
…
});
SUPER()
81
App.DefaultPlayer = Em.Object.extend({
init: function () {
this.set('imgProfilePrefix', 'default_');
this.set('imgProfileSuffix', '_profile');
}
});
!
App.Player = App.DefaultPlayer.extend({
init: function () {
this._super();
this.set('imgProfilePrefix', 'player_');
}
});
COMPUTED PROPERTIES
82
App.DefaultPlayer = Ember.Object.extend({
…
name: "Steve",
baseDir: "/images",
imgName: function(){
return this.get('imgProfilePrefix') + this.get('name').split('
').join('_').toLowerCase() + this.get('imgProfileSuffix') + '.png';
},
imgPath: function(){
return this.get('baseDir') + '/profile/' + this.imgName();
}.property('baseDir', 'imgName')
});
OBSERVERS
83
App.DefaultPlayer = Ember.Object.extend({
…
onlineStatusChanged: function(){
console.log('onlineStatusChanged to: ' + this.get('isOnline'));
}.observes('isOnline').on('init')
});
!
var steve = App.DefaultPlayer.create({
'isOnline': true
}); // onlineStatusChanged to true
!
steve.set('isOnline', false); // onlineStatusChanged to false
BINDINGS
84
App.DefaultPlayer = Ember.Object.extend({
…
name: "Steve",
baseDir: "/images",
imgName: function(){
return this.get('imgProfilePrefix') + this.get('name').split('
').join('_').toLowerCase() + this.get('imgProfileSuffix') + '.png';
},
imgPath: function(){
return this.get('baseDir') + '/profile/' + this.imgName();
}.property('baseDir', 'imgName')
});
EMBER RUN LOOP ||
BACKBURNER.JS
POST LOADED
86
Container App
HTML5/CSS3
Web Framework
HTML5/CSS3/JavaScript
Render Engine
JavaScript DOM creation
&& String templates
Gadget App 1
iFrame
Gadget App 2
iFrame
Gadget App 3
iFrame
REQ PARAMs
Iframe Refresh
2007
POST LOADED
87
Container App
HTML5/CSS3
Web Framework
HTML5/CSS3/JavaScript
Render Engine
JavaScript DOM creation
&& String templates
{
action:”moveGadget",
version:1,
category:category,
order:order
};
XHR REQUEST
-JSON ACTION OBJECT
Gadget App 1
iFrame
Gadget App 2
iFrame
Gadget App 3
iFrame
x
REQ PARAMs
Iframe Refresh
DRAG N’ DROP EVENT FIRES!
2007
POST LOADED
88
Container App
HTML5/CSS3
Web Framework
HTML5/CSS3/JavaScript
Render Engine
JavaScript DOM creation
&& String templates
{
action:”moveGadget",
version:1,
category:category,
order:order
};
XHR REQUEST
-JSON ACTION OBJECT
Gadget App 1
iFrame
Gadget App 2
iFrame
Gadget App 3
iFrame
x
REQ PARAMs
Iframe Refresh
x
{
action:”moveGadget",
version:1,
category:category,
order:order
};
XHR REQUEST
-JSON ACTION OBJECT
2007
RUN LOOP
89
!
BBone.DisplayView = Backbone.View.extend({
!
initialize: function () {
this.listenTo(this.model, 'change', this.render);
},
render: function() {
console.log(‘render’);
}
});
!
// render
model.set('firstName', 'Erik');
// render again
model.set('lastName', 'Bryn');
!
!
ACTIONS ARE DEFERRED
!
RUN LOOP
91
!
BBone.DisplayView = Backbone.View.extend({
initialize: function () {
this.listenTo(this.model, 'change', this.render);
},
render: function() {
backburner.deferOnce('render', this, this.actuallyRender);
},
actuallyRender: function() {
// do our DOM manipulations here. will only be called once.
}
});
backburner.run(function() {
model.set('firstName', 'Erik');
model.set('lastName', 'Bryn');
});
!
!
EMBER.RUN.QUEUES
!
FLUSHING ROUTER TRANSITIONS
!
["SYNC", “ACTIONS", "ROUTERTRANSITIONS", "RENDER", "AFTERRENDER", "DESTROY"]
!
EMBER.RUN.QUEUES
!
["SYNC", "ACTIONS",
"ROUTERTRANSITIONS", "RENDER",
"AFTERRENDER", "DESTROY"]
AINT’ THAT
FANCY!
JS TEMPLATES
DOM
96
Container App
HTML5/CSS3
Web Framework
HTML5/CSS3/JavaScript
Render Engine
JavaScript DOM creation
&& String templates
JSON
MARKUP
LANGUAGE
Main.createNode: function(type, id, classNames) {
var node = document.createElement(type);
node.id = id;
if (typeof classNames === 'string' ) {
node.className = classNames;
}
else if (typeof classNames === 'object' ){
var str = classNames.toString();
var classString=str.replace(/,/g,' ');
node.className = classString;
}
return node;
}
2007
DOM VS INNERHTML
97
<script type="text/x-handlebars" data-template-
name=“application">
!
<!-- template code here -->
!
</script>
2007
DOM VS INNERHTML
98
2008
INNERHTML
99
Container App
HTML5/CSS3
Web Framework
HTML5/CSS3/JavaScript
Render Engine
JavaScript DOM creation
&& String templates
gadgets.Gadget.prototype.render = function(chrome) {
if (chrome) {
this.getContent(function(content) {
chrome.innerHTML = content;
});
}
};
!
2007
JSON
MARKUP
LANGUAGE
JS TEMPLATES WITH HANDLEBARS
!
Ember.TEMPLATES
HANDLEBARS
101
<div {{bind-attr
class=“myClass"}}>
{{myValue}}
</div>
Compiled JS
Functions
!
Em.TEMPLATES
Handlebars
Compiler
Emits
String
!
	
  	
  
//This	
  is	
  how	
  handlebars	
  works	
  
var	
  output	
  =	
  "";	
  
output.push("<div	
  class="");	
  
output.push("<script	
  type='text/x-­‐placeholder'	
  id='start-­‐1'></script>");	
  
//	
  insert	
  the	
  value	
  of	
  myClass	
  
output.push("<script	
  type='text/x-­‐placeholder'	
  id='end-­‐1'></script>");	
  
output.push("">");	
  
output.push("<script	
  type='text/x-­‐placeholder'	
  id='start-­‐2'></script>");	
  
//	
  insert	
  the	
  value	
  of	
  myValue	
  
output.push("<script	
  type='text/x-­‐placeholder'	
  id='end-­‐2'></script>");	
  
output.push("</div>");
Output
string
innerHTML
HANDLEBARS
102
<script type="text/x-handlebars" data-template-
name=“application">
<!-- template code here -->
</script>
grunt.initConfig({
yeoman: yeomanConfig,
watch: {
emberTemplates: {
files: '<%= yeoman.app %>/templates/**/*.hbs',
tasks: ['emberTemplates', 'livereload']
}
}
});
VARIABLES
103
{{App.applicationName}}
<ul class="navbar artists”>
{{#each item in navbar-items}}
{{#if item.isAccessible}}
{{#each label in items.labels}}
<li>
{{#linkTo ‘label’ label.id}}{{label.title}}{{/linkTo}}
</li>
{{/each}}
{{else}}
<li>
<a {{bind-attr href=‘item.fullAddress’}}>
{{item.name}}</a>
</li>
{{/if}}
{{/each}}
</ul>
MINIMAL LOGIC
104
{{App.applicationName}}
<ul class="navbar artists”>
{{#each item in navbar-items}}
{{#if item.isAccessible}}
{{#each label in items.labels}}
<li>
{{#linkTo ‘label’ label.id}}{{label.title}}{{/linkTo}}
</li>
{{/each}}
{{else}}
<li>
<a {{bind-attr href=‘item.fullAddress’}}>
{{item.name}}</a>
</li>
{{/if}}
{{/each}}
</ul>
LINKS
105
{{App.applicationName}}
<ul class="navbar artists”>
{{#each item in navbar-items}}
{{#if item.isAccessible}}
{{#each label in items.labels}}
<li>
{{#linkTo ‘label’ label.id}}{{label.title}}{{/linkTo}}
</li>
{{/each}}
{{else}}
<li>
<a {{bind-attr href=‘item.fullAddress’}}>
{{item.name}}</a>
</li>
{{/if}}
{{/each}}
</ul>
LISTS
106
{{App.applicationName}}
<ul class="navbar artists”>
{{#each item in navbar-items}}
{{#if item.isAccessible}}
{{#each label in item.labels}}
<li>
{{#linkTo ‘label’ label.id}}{{label.title}}{{/linkTo}}
</li>
{{/each}}
{{else}}
<li>
<a {{bind-attr href=‘item.fullAddress’}}>
{{item.name}}</a> </li>
{{/if}}
{{/each}}
</ul>
BOUND ATTRIBUTES
107
{{App.applicationName}}
<ul class="navbar artists”>
{{#each item in navbar-items}}
{{#if item.isAccessible}}
{{#each label in items.labels}}
<li>
{{#linkTo ‘label’ label.id}}{{label.title}}{{/linkTo}}
</li>
{{/each}}
{{else}}
<li>
<a {{bind-attr href=‘item.fullAddress’}}>
{{item.name}}</a>
</li>
{{/if}}
{{/each}}
</ul>
!
HTMLBARS
!
!
HTMLBARS OVER HANDLEBARS
PERFORMANCE
!
BIND-ATTR GONE
!
METAMORPH GONE
!
LOGIC IN TEMPLATES
!
!
HTMLBARS
110
<div	
  
class=“{{myClass}}”>	
  
{{myValue}}	
  
</div>
Compiled JS
Functions
!
Em.TEMPLATES
HTMLBars Compiler Emits DOM elements
var	
  output	
  =	
  dom.createDocumentFragment();	
  
var	
  div	
  =	
  dom.createElement('div');	
  
dom.RESOLVE_ATTR(context,	
  div,	
  'class',	
  'myClass');	
  
var	
  text	
  =	
  dom.createTextNode();	
  
dom.RESOLVE(context,	
  text,	
  'textContent',	
  'myValue');	
  
div.appendChild(text);	
  
output.appendChild(div);
<div	
  class="{{myClass}}">{{myValue}}</div>
BOUND ATTRIBUTES
111
{{App.applicationName}}
<ul class="navbar artists”>
{{#each item in navbar-items}}
{{#if item.isAccessible}}
{{#each label in items.labels}}
<li>
{{#linkTo ‘label’ label.id}}{{label.title}}{{/linkTo}}
</li>
{{/each}}
{{else}}
<li>
<a {{bind-attr href=‘item.fullAddress’}}>
{{item.name}}</a>
</li>
{{/if}}
{{/each}}
</ul>
NO MORE BIND-ATTR
112
{{App.applicationName}}
<ul class="navbar artists”>
{{#each item in navbar-items}}
{{#if item.isAccessible}}
{{#each label in items.labels}}
<li>
{{#linkTo ‘label’ label.id}}{{label.title}}{{/linkTo}}
</li>
{{/each}}
{{else}}
<li>
<a href=“{{fullAddress}}”>
{{item.name}}</a>
</li>
{{/if}}
{{/each}}
</ul>
LOGIC-LESS
113
{{App.applicationName}}
<ul class="navbar artists”>
{{#each item in navbar-items}}
{{#if item.isAccessible}}
{{#each label in items.labels}}
<li>
{{#linkTo ‘label’ label.id}}{{label.title}}{{/linkTo}}
</li>
{{/each}}
{{else}}
<li>
<a href=“{{fullAddress}}”>
{{item.name}}</a>
</li>
{{/if}}
{{/each}}
</ul>
LOGIC
114
{{App.applicationName}}
<ul class="navbar artists”>
{{#each item in navbar-items}}
{{#if (item.type === ‘sidenavbar-item’) }}
{{#each label in items.labels}}
<li>
{{#linkTo ‘label’ label.id}}{{label.title}}{{/linkTo}}
</li>
{{/each}}
{{else}}
<li>
<a href=“{{fullAddress}}”>
{{item.name}}</a>
</li>
{{/if}}
{{/each}}
</ul>
HTMLBARS
115
<script type="text/x-handlebars" data-template-
name=“application">
!
<!-- template code here -->
!
</script>
METAMORPHS
116
PROMISES AND THE ASYNC
ROUTER
!
!
RSVP
PROMISES/A+
!
ES6 COMPLIANT
!
CONVENIENCE METHODS
!
!
!
!
!
!
RSVP
120
var p = new RSVP.Promise(function(resolve, reject) {
// succeed
resolve(value);
// or reject
reject(error);
});
!
p.then(function(value) {
// success
}, function(value) {
// failure
});
CONTINUATION
121
Container App
HTML5/CSS3
Web Framework
HTML5/CSS3/JavaScript
Render Engine
JavaScript DOM creation
&& String templates
!
gadgets.Gadget.prototype.getContent = function(continuation) {
gadgets.callAsyncAndJoin(
[this.getTitleBarContent, this.getUserPrefsDialogContent, this.getMainContent],
function(results) {continuation(results.join(''));},
this);
};
!
gadgets.Gadget.prototype.render = function(chrome) {
if (chrome) {
this.getContent(function(content) {
chrome.innerHTML = content;
});
}
};
! 2007
CONTINUATION
122
!
gadgets.Gadget.prototype.getContent = function(continuation) {
gadgets.callAsyncAndJoin(
[this.getTitleBarContent, this.getUserPrefsDialogContent,
this.getMainContent],
function(results) {continuation(results.join(''));},
this);
};
!
gadgets.Gadget.prototype.render = function(chrome) {
if (chrome) {
this.getContent(function(content) {
chrome.innerHTML = content;
});
}
};
!
2007
XHR RESPONSE
123
Container App
HTML5/CSS3
Web Framework
HTML5/CSS3/JavaScript
Render Engine
JavaScript DOM creation
&& String templates
{
"root": “#portal",
"childrenType": "Portal",
"type": "ClientCommandObject",
"children": [{
"childrenType": "TabContainer",
"type": "Portal",
"children": [{
"childrenType": "TabPage",
"type": "TabContainer",
"children": [{
"children": [{
"childrenType": "Gadget",
"type": "Column",
"children": [{
"gadgetType": "MyAccounts",
"gadgetContentType": {
"type": "url"
}
}, {
"gadgetType": "EntOffersMlp",
"gadgetContentType": {
"type": "url"
}
}, {
"gadgetType": "SpendingPlan",
"gadgetContentType": {
"type": "url"
}
}, {
"gadgetType": "ImcoStorefront",
"gadgetContentType": {
"type": "url"
}
},
XHR RESPONSE
-JSON MARKUP FORMAT
Gadget App 1
iFrame
Gadget App 2
iFrame
Gadget App 3
iFrame
x
REQ PARAMs
Iframe Refresh
2007
SUCCESS, FAILURE
124
Main.YUIConnectionManager.callback = {
success: function(o) {
try {
var data = YAHOO.lang.JSON.parse(o.responseText);
}
catch (e) {
Main.debug(err + " - Invalid data”);
}
},
failure: function(o) {
}
};
2007
ROUTE HANDLERS
125
App.ArtistRoute = Ember.Route.extend({
model: function(params) {
!
XHR( "some URL” , {"id":params.enid}, function
callback(response){
// handle response
});
!
}
});
PROMISES
126
RSVP.all([ afunction(), another(), yetAnother()])
!
.then(function() {
!
console.log("They're all finished, success is ours!”);
!
}, function() {
!
console.error("One or more FAILED!”);
});
PROMISES
127
var promises = {
posts: getJSON("/posts.json"),
users: getJSON("/users.json")
};
!
RSVP.hash(promises).then(function(results) {
console.log(results.users) // print the users.json results
console.log(results.posts) // print the posts.json results
});
PRESENT AND FUTURE
!
DESIGN WITH CODE
!
WORK FRONT TO BACK
!
THE EMBER WAY
!
THE EMBER OBJECT MODEL
!
EMBER RUN LOOP AND BACKBURNER
!
JS TEMPLATES W/ HANDLEBARS / HTMLBARS
!
PROMISES AND THE ASYNC ROUTER
!
WEB COMPONENTS
!
!
!
!
!
!
!
WEB COMPONENTS
IFRAMES
!
TRADITIONAL WEB DEVELOPERS CAN ADD CONTENT
!
SANDBOXED CONTENT / CAN LOAD FROM PROXIES
!
POST MESSAGE API HAS EVOLVED / CONTAINER CAN CREAT AN INTERFACE
!
DONT NEED TO LEARN CONTAINER IMPLEMENTATION
!
!
!
!
!
!
!
!
!
!
!
!
!
THAT’S NASTY
OH WAIT, ONE MORE THING.
!
- ERIK BRYN, EMBER CONF 2014
THE FUTURE IS NOW
The Art and Science of Shipping Ember Apps

More Related Content

What's hot

Intro to React - Featuring Modern JavaScript
Intro to React - Featuring Modern JavaScriptIntro to React - Featuring Modern JavaScript
Intro to React - Featuring Modern JavaScriptjasonsich
 
HTML5 & CSS3 refresher for mobile apps
HTML5 & CSS3 refresher for mobile appsHTML5 & CSS3 refresher for mobile apps
HTML5 & CSS3 refresher for mobile appsIvano Malavolta
 
Kann JavaScript elegant sein?
Kann JavaScript elegant sein?Kann JavaScript elegant sein?
Kann JavaScript elegant sein?jbandi
 
From Backbone to Ember and Back(bone) Again
From Backbone to Ember and Back(bone) AgainFrom Backbone to Ember and Back(bone) Again
From Backbone to Ember and Back(bone) Againjonknapp
 
ForwardJS 2017 - Fullstack end-to-end Test Automation with node.js
ForwardJS 2017 -  Fullstack end-to-end Test Automation with node.jsForwardJS 2017 -  Fullstack end-to-end Test Automation with node.js
ForwardJS 2017 - Fullstack end-to-end Test Automation with node.jsMek Srunyu Stittri
 
React && React Native workshop
React && React Native workshopReact && React Native workshop
React && React Native workshopStacy Goh
 
...and thus your forms automagically disappeared
...and thus your forms automagically disappeared...and thus your forms automagically disappeared
...and thus your forms automagically disappearedLuc Bors
 
React Nativeはクロスプラットフォームモバイルアプリ開発の夢を見るか #DroidKaigi
React Nativeはクロスプラットフォームモバイルアプリ開発の夢を見るか #DroidKaigiReact Nativeはクロスプラットフォームモバイルアプリ開発の夢を見るか #DroidKaigi
React Nativeはクロスプラットフォームモバイルアプリ開発の夢を見るか #DroidKaigiYukiya Nakagawa
 
How and why we evolved a legacy Java web application to Scala... and we are s...
How and why we evolved a legacy Java web application to Scala... and we are s...How and why we evolved a legacy Java web application to Scala... and we are s...
How and why we evolved a legacy Java web application to Scala... and we are s...Katia Aresti
 
Ajax Performance
Ajax PerformanceAjax Performance
Ajax Performancekaven yan
 
High Performance Ajax Applications
High Performance Ajax ApplicationsHigh Performance Ajax Applications
High Performance Ajax ApplicationsJulien Lecomte
 
ActiveJDBC - ActiveRecord implementation in Java
ActiveJDBC - ActiveRecord implementation in JavaActiveJDBC - ActiveRecord implementation in Java
ActiveJDBC - ActiveRecord implementation in Javaipolevoy
 
Intro To JavaScript Unit Testing - Ran Mizrahi
Intro To JavaScript Unit Testing - Ran MizrahiIntro To JavaScript Unit Testing - Ran Mizrahi
Intro To JavaScript Unit Testing - Ran MizrahiRan Mizrahi
 
ActiveWeb: Chicago Java User Group Presentation
ActiveWeb: Chicago Java User Group PresentationActiveWeb: Chicago Java User Group Presentation
ActiveWeb: Chicago Java User Group Presentationipolevoy
 
Intro to jQuery @ Startup Institute
Intro to jQuery @ Startup InstituteIntro to jQuery @ Startup Institute
Intro to jQuery @ Startup InstituteRafael Gonzaque
 

What's hot (20)

Intro to React - Featuring Modern JavaScript
Intro to React - Featuring Modern JavaScriptIntro to React - Featuring Modern JavaScript
Intro to React - Featuring Modern JavaScript
 
HTML5 & CSS3 refresher for mobile apps
HTML5 & CSS3 refresher for mobile appsHTML5 & CSS3 refresher for mobile apps
HTML5 & CSS3 refresher for mobile apps
 
Huge web apps web expo 2013
Huge web apps web expo 2013Huge web apps web expo 2013
Huge web apps web expo 2013
 
Kann JavaScript elegant sein?
Kann JavaScript elegant sein?Kann JavaScript elegant sein?
Kann JavaScript elegant sein?
 
From Backbone to Ember and Back(bone) Again
From Backbone to Ember and Back(bone) AgainFrom Backbone to Ember and Back(bone) Again
From Backbone to Ember and Back(bone) Again
 
Ugo Cei Presentation
Ugo Cei PresentationUgo Cei Presentation
Ugo Cei Presentation
 
ForwardJS 2017 - Fullstack end-to-end Test Automation with node.js
ForwardJS 2017 -  Fullstack end-to-end Test Automation with node.jsForwardJS 2017 -  Fullstack end-to-end Test Automation with node.js
ForwardJS 2017 - Fullstack end-to-end Test Automation with node.js
 
React && React Native workshop
React && React Native workshopReact && React Native workshop
React && React Native workshop
 
...and thus your forms automagically disappeared
...and thus your forms automagically disappeared...and thus your forms automagically disappeared
...and thus your forms automagically disappeared
 
React Nativeはクロスプラットフォームモバイルアプリ開発の夢を見るか #DroidKaigi
React Nativeはクロスプラットフォームモバイルアプリ開発の夢を見るか #DroidKaigiReact Nativeはクロスプラットフォームモバイルアプリ開発の夢を見るか #DroidKaigi
React Nativeはクロスプラットフォームモバイルアプリ開発の夢を見るか #DroidKaigi
 
How and why we evolved a legacy Java web application to Scala... and we are s...
How and why we evolved a legacy Java web application to Scala... and we are s...How and why we evolved a legacy Java web application to Scala... and we are s...
How and why we evolved a legacy Java web application to Scala... and we are s...
 
Ajax Performance
Ajax PerformanceAjax Performance
Ajax Performance
 
High Performance Ajax Applications
High Performance Ajax ApplicationsHigh Performance Ajax Applications
High Performance Ajax Applications
 
ActiveJDBC - ActiveRecord implementation in Java
ActiveJDBC - ActiveRecord implementation in JavaActiveJDBC - ActiveRecord implementation in Java
ActiveJDBC - ActiveRecord implementation in Java
 
Javascript Best Practices
Javascript Best PracticesJavascript Best Practices
Javascript Best Practices
 
Intro To JavaScript Unit Testing - Ran Mizrahi
Intro To JavaScript Unit Testing - Ran MizrahiIntro To JavaScript Unit Testing - Ran Mizrahi
Intro To JavaScript Unit Testing - Ran Mizrahi
 
ActiveWeb: Chicago Java User Group Presentation
ActiveWeb: Chicago Java User Group PresentationActiveWeb: Chicago Java User Group Presentation
ActiveWeb: Chicago Java User Group Presentation
 
"Javascript" por Tiago Rodrigues
"Javascript" por Tiago Rodrigues"Javascript" por Tiago Rodrigues
"Javascript" por Tiago Rodrigues
 
Intro to jQuery @ Startup Institute
Intro to jQuery @ Startup InstituteIntro to jQuery @ Startup Institute
Intro to jQuery @ Startup Institute
 
Mvvm and KnockoutJS
Mvvm and KnockoutJSMvvm and KnockoutJS
Mvvm and KnockoutJS
 

Similar to The Art and Science of Shipping Ember Apps

Integrating React.js Into a PHP Application
Integrating React.js Into a PHP ApplicationIntegrating React.js Into a PHP Application
Integrating React.js Into a PHP ApplicationAndrew Rota
 
Get Hip with JHipster: Spring Boot + AngularJS + Bootstrap - Devoxx France 2016
Get Hip with JHipster: Spring Boot + AngularJS + Bootstrap - Devoxx France 2016Get Hip with JHipster: Spring Boot + AngularJS + Bootstrap - Devoxx France 2016
Get Hip with JHipster: Spring Boot + AngularJS + Bootstrap - Devoxx France 2016Matt Raible
 
(2018) Webpack Encore - Asset Management for the rest of us
(2018) Webpack Encore - Asset Management for the rest of us(2018) Webpack Encore - Asset Management for the rest of us
(2018) Webpack Encore - Asset Management for the rest of usStefan Adolf
 
Sparkling Water Applications Meetup 07.21.15
Sparkling Water Applications Meetup 07.21.15Sparkling Water Applications Meetup 07.21.15
Sparkling Water Applications Meetup 07.21.15Sri Ambati
 
HTML5 for the Silverlight Guy
HTML5 for the Silverlight GuyHTML5 for the Silverlight Guy
HTML5 for the Silverlight GuyDavid Padbury
 
[Coscup 2012] JavascriptMVC
[Coscup 2012] JavascriptMVC[Coscup 2012] JavascriptMVC
[Coscup 2012] JavascriptMVCAlive Kuo
 
Object Oriented Programming In JavaScript
Object Oriented Programming In JavaScriptObject Oriented Programming In JavaScript
Object Oriented Programming In JavaScriptForziatech
 
Get Hip with JHipster: Spring Boot + AngularJS + Bootstrap - Devoxx UK 2016
Get Hip with JHipster: Spring Boot + AngularJS + Bootstrap - Devoxx UK 2016Get Hip with JHipster: Spring Boot + AngularJS + Bootstrap - Devoxx UK 2016
Get Hip with JHipster: Spring Boot + AngularJS + Bootstrap - Devoxx UK 2016Matt Raible
 
Intro to-html-backbone
Intro to-html-backboneIntro to-html-backbone
Intro to-html-backbonezonathen
 
WebNet Conference 2012 - Designing complex applications using html5 and knock...
WebNet Conference 2012 - Designing complex applications using html5 and knock...WebNet Conference 2012 - Designing complex applications using html5 and knock...
WebNet Conference 2012 - Designing complex applications using html5 and knock...Fabio Franzini
 
Java Full Stack Curriculum
Java Full Stack Curriculum Java Full Stack Curriculum
Java Full Stack Curriculum NxtWave
 
Crash Course HTML/Rails Slides
Crash Course HTML/Rails SlidesCrash Course HTML/Rails Slides
Crash Course HTML/Rails SlidesUdita Plaha
 
SproutCore and the Future of Web Apps
SproutCore and the Future of Web AppsSproutCore and the Future of Web Apps
SproutCore and the Future of Web AppsMike Subelsky
 
Angular from a Different Angle
Angular from a Different AngleAngular from a Different Angle
Angular from a Different AngleJeremy Likness
 
Alberto Maria Angelo Paro - Isomorphic programming in Scala and WebDevelopmen...
Alberto Maria Angelo Paro - Isomorphic programming in Scala and WebDevelopmen...Alberto Maria Angelo Paro - Isomorphic programming in Scala and WebDevelopmen...
Alberto Maria Angelo Paro - Isomorphic programming in Scala and WebDevelopmen...Codemotion
 
Front End Development for Back End Java Developers - Jfokus 2020
Front End Development for Back End Java Developers - Jfokus 2020Front End Development for Back End Java Developers - Jfokus 2020
Front End Development for Back End Java Developers - Jfokus 2020Matt Raible
 

Similar to The Art and Science of Shipping Ember Apps (20)

Integrating React.js Into a PHP Application
Integrating React.js Into a PHP ApplicationIntegrating React.js Into a PHP Application
Integrating React.js Into a PHP Application
 
Get Hip with JHipster: Spring Boot + AngularJS + Bootstrap - Devoxx France 2016
Get Hip with JHipster: Spring Boot + AngularJS + Bootstrap - Devoxx France 2016Get Hip with JHipster: Spring Boot + AngularJS + Bootstrap - Devoxx France 2016
Get Hip with JHipster: Spring Boot + AngularJS + Bootstrap - Devoxx France 2016
 
(2018) Webpack Encore - Asset Management for the rest of us
(2018) Webpack Encore - Asset Management for the rest of us(2018) Webpack Encore - Asset Management for the rest of us
(2018) Webpack Encore - Asset Management for the rest of us
 
Oracle APEX & PhoneGap
Oracle APEX & PhoneGapOracle APEX & PhoneGap
Oracle APEX & PhoneGap
 
Sparkling Water Applications Meetup 07.21.15
Sparkling Water Applications Meetup 07.21.15Sparkling Water Applications Meetup 07.21.15
Sparkling Water Applications Meetup 07.21.15
 
HTML5 for the Silverlight Guy
HTML5 for the Silverlight GuyHTML5 for the Silverlight Guy
HTML5 for the Silverlight Guy
 
[Coscup 2012] JavascriptMVC
[Coscup 2012] JavascriptMVC[Coscup 2012] JavascriptMVC
[Coscup 2012] JavascriptMVC
 
Object Oriented Programming In JavaScript
Object Oriented Programming In JavaScriptObject Oriented Programming In JavaScript
Object Oriented Programming In JavaScript
 
Get Hip with JHipster: Spring Boot + AngularJS + Bootstrap - Devoxx UK 2016
Get Hip with JHipster: Spring Boot + AngularJS + Bootstrap - Devoxx UK 2016Get Hip with JHipster: Spring Boot + AngularJS + Bootstrap - Devoxx UK 2016
Get Hip with JHipster: Spring Boot + AngularJS + Bootstrap - Devoxx UK 2016
 
Intro to-html-backbone
Intro to-html-backboneIntro to-html-backbone
Intro to-html-backbone
 
WebNet Conference 2012 - Designing complex applications using html5 and knock...
WebNet Conference 2012 - Designing complex applications using html5 and knock...WebNet Conference 2012 - Designing complex applications using html5 and knock...
WebNet Conference 2012 - Designing complex applications using html5 and knock...
 
Java Full Stack Curriculum
Java Full Stack Curriculum Java Full Stack Curriculum
Java Full Stack Curriculum
 
Crash Course HTML/Rails Slides
Crash Course HTML/Rails SlidesCrash Course HTML/Rails Slides
Crash Course HTML/Rails Slides
 
SproutCore and the Future of Web Apps
SproutCore and the Future of Web AppsSproutCore and the Future of Web Apps
SproutCore and the Future of Web Apps
 
Full Stack Scala
Full Stack ScalaFull Stack Scala
Full Stack Scala
 
Angular from a Different Angle
Angular from a Different AngleAngular from a Different Angle
Angular from a Different Angle
 
Alberto Maria Angelo Paro - Isomorphic programming in Scala and WebDevelopmen...
Alberto Maria Angelo Paro - Isomorphic programming in Scala and WebDevelopmen...Alberto Maria Angelo Paro - Isomorphic programming in Scala and WebDevelopmen...
Alberto Maria Angelo Paro - Isomorphic programming in Scala and WebDevelopmen...
 
Play framework
Play frameworkPlay framework
Play framework
 
Node.JS briefly introduced
Node.JS briefly introducedNode.JS briefly introduced
Node.JS briefly introduced
 
Front End Development for Back End Java Developers - Jfokus 2020
Front End Development for Back End Java Developers - Jfokus 2020Front End Development for Back End Java Developers - Jfokus 2020
Front End Development for Back End Java Developers - Jfokus 2020
 

More from Jesse Cravens

Oredev 2013: Building Web Apps with Ember.js
Oredev 2013: Building Web Apps with Ember.jsOredev 2013: Building Web Apps with Ember.js
Oredev 2013: Building Web Apps with Ember.jsJesse Cravens
 
JavaScript Makers: How JS is Helping Drive the Maker Movement
JavaScript Makers: How JS is Helping Drive the Maker MovementJavaScript Makers: How JS is Helping Drive the Maker Movement
JavaScript Makers: How JS is Helping Drive the Maker MovementJesse Cravens
 
HTML5.tx 2013: Embedded JavaScript, HTML5 and the Internet of Things
HTML5.tx 2013: Embedded JavaScript, HTML5 and the Internet of ThingsHTML5.tx 2013: Embedded JavaScript, HTML5 and the Internet of Things
HTML5.tx 2013: Embedded JavaScript, HTML5 and the Internet of ThingsJesse Cravens
 
Client Server 3.0 - 6 Ways JavaScript is Revolutionizing the Client/Server Re...
Client Server 3.0 - 6 Ways JavaScript is Revolutionizing the Client/Server Re...Client Server 3.0 - 6 Ways JavaScript is Revolutionizing the Client/Server Re...
Client Server 3.0 - 6 Ways JavaScript is Revolutionizing the Client/Server Re...Jesse Cravens
 
Rapid Prototyping HTML5 Applications with Node.js
Rapid Prototyping HTML5 Applications with Node.jsRapid Prototyping HTML5 Applications with Node.js
Rapid Prototyping HTML5 Applications with Node.jsJesse Cravens
 

More from Jesse Cravens (6)

Oredev 2013: Building Web Apps with Ember.js
Oredev 2013: Building Web Apps with Ember.jsOredev 2013: Building Web Apps with Ember.js
Oredev 2013: Building Web Apps with Ember.js
 
JavaScript Makers: How JS is Helping Drive the Maker Movement
JavaScript Makers: How JS is Helping Drive the Maker MovementJavaScript Makers: How JS is Helping Drive the Maker Movement
JavaScript Makers: How JS is Helping Drive the Maker Movement
 
Sxsw2013
Sxsw2013Sxsw2013
Sxsw2013
 
HTML5.tx 2013: Embedded JavaScript, HTML5 and the Internet of Things
HTML5.tx 2013: Embedded JavaScript, HTML5 and the Internet of ThingsHTML5.tx 2013: Embedded JavaScript, HTML5 and the Internet of Things
HTML5.tx 2013: Embedded JavaScript, HTML5 and the Internet of Things
 
Client Server 3.0 - 6 Ways JavaScript is Revolutionizing the Client/Server Re...
Client Server 3.0 - 6 Ways JavaScript is Revolutionizing the Client/Server Re...Client Server 3.0 - 6 Ways JavaScript is Revolutionizing the Client/Server Re...
Client Server 3.0 - 6 Ways JavaScript is Revolutionizing the Client/Server Re...
 
Rapid Prototyping HTML5 Applications with Node.js
Rapid Prototyping HTML5 Applications with Node.jsRapid Prototyping HTML5 Applications with Node.js
Rapid Prototyping HTML5 Applications with Node.js
 

Recently uploaded

SOCRadar Research Team: Latest Activities of IntelBroker
SOCRadar Research Team: Latest Activities of IntelBrokerSOCRadar Research Team: Latest Activities of IntelBroker
SOCRadar Research Team: Latest Activities of IntelBrokerSOCRadar
 
Mastering Windows 7 A Comprehensive Guide for Power Users .pdf
Mastering Windows 7 A Comprehensive Guide for Power Users .pdfMastering Windows 7 A Comprehensive Guide for Power Users .pdf
Mastering Windows 7 A Comprehensive Guide for Power Users .pdfmbmh111980
 
Breaking the Code : A Guide to WhatsApp Business API.pdf
Breaking the Code : A Guide to WhatsApp Business API.pdfBreaking the Code : A Guide to WhatsApp Business API.pdf
Breaking the Code : A Guide to WhatsApp Business API.pdfMeon Technology
 
top nidhi software solution freedownload
top nidhi software solution freedownloadtop nidhi software solution freedownload
top nidhi software solution freedownloadvrstrong314
 
Gamify Your Mind; The Secret Sauce to Delivering Success, Continuously Improv...
Gamify Your Mind; The Secret Sauce to Delivering Success, Continuously Improv...Gamify Your Mind; The Secret Sauce to Delivering Success, Continuously Improv...
Gamify Your Mind; The Secret Sauce to Delivering Success, Continuously Improv...Shahin Sheidaei
 
Facemoji Keyboard released its 2023 State of Emoji report, outlining the most...
Facemoji Keyboard released its 2023 State of Emoji report, outlining the most...Facemoji Keyboard released its 2023 State of Emoji report, outlining the most...
Facemoji Keyboard released its 2023 State of Emoji report, outlining the most...rajkumar669520
 
Crafting the Perfect Measurement Sheet with PLM Integration
Crafting the Perfect Measurement Sheet with PLM IntegrationCrafting the Perfect Measurement Sheet with PLM Integration
Crafting the Perfect Measurement Sheet with PLM IntegrationWave PLM
 
Field Employee Tracking System| MiTrack App| Best Employee Tracking Solution|...
Field Employee Tracking System| MiTrack App| Best Employee Tracking Solution|...Field Employee Tracking System| MiTrack App| Best Employee Tracking Solution|...
Field Employee Tracking System| MiTrack App| Best Employee Tracking Solution|...informapgpstrackings
 
Beyond Event Sourcing - Embracing CRUD for Wix Platform - Java.IL
Beyond Event Sourcing - Embracing CRUD for Wix Platform - Java.ILBeyond Event Sourcing - Embracing CRUD for Wix Platform - Java.IL
Beyond Event Sourcing - Embracing CRUD for Wix Platform - Java.ILNatan Silnitsky
 
TROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERROR
TROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERRORTROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERROR
TROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERRORTier1 app
 
iGaming Platform & Lottery Solutions by Skilrock
iGaming Platform & Lottery Solutions by SkilrockiGaming Platform & Lottery Solutions by Skilrock
iGaming Platform & Lottery Solutions by SkilrockSkilrock Technologies
 
Prosigns: Transforming Business with Tailored Technology Solutions
Prosigns: Transforming Business with Tailored Technology SolutionsProsigns: Transforming Business with Tailored Technology Solutions
Prosigns: Transforming Business with Tailored Technology SolutionsProsigns
 
How Does XfilesPro Ensure Security While Sharing Documents in Salesforce?
How Does XfilesPro Ensure Security While Sharing Documents in Salesforce?How Does XfilesPro Ensure Security While Sharing Documents in Salesforce?
How Does XfilesPro Ensure Security While Sharing Documents in Salesforce?XfilesPro
 
Designing for Privacy in Amazon Web Services
Designing for Privacy in Amazon Web ServicesDesigning for Privacy in Amazon Web Services
Designing for Privacy in Amazon Web ServicesKrzysztofKkol1
 
Advanced Flow Concepts Every Developer Should Know
Advanced Flow Concepts Every Developer Should KnowAdvanced Flow Concepts Every Developer Should Know
Advanced Flow Concepts Every Developer Should KnowPeter Caitens
 
Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...
Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...
Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...Anthony Dahanne
 
AI/ML Infra Meetup | Improve Speed and GPU Utilization for Model Training & S...
AI/ML Infra Meetup | Improve Speed and GPU Utilization for Model Training & S...AI/ML Infra Meetup | Improve Speed and GPU Utilization for Model Training & S...
AI/ML Infra Meetup | Improve Speed and GPU Utilization for Model Training & S...Alluxio, Inc.
 
De mooiste recreatieve routes ontdekken met RouteYou en FME
De mooiste recreatieve routes ontdekken met RouteYou en FMEDe mooiste recreatieve routes ontdekken met RouteYou en FME
De mooiste recreatieve routes ontdekken met RouteYou en FMEJelle | Nordend
 
Accelerate Enterprise Software Engineering with Platformless
Accelerate Enterprise Software Engineering with PlatformlessAccelerate Enterprise Software Engineering with Platformless
Accelerate Enterprise Software Engineering with PlatformlessWSO2
 

Recently uploaded (20)

SOCRadar Research Team: Latest Activities of IntelBroker
SOCRadar Research Team: Latest Activities of IntelBrokerSOCRadar Research Team: Latest Activities of IntelBroker
SOCRadar Research Team: Latest Activities of IntelBroker
 
Mastering Windows 7 A Comprehensive Guide for Power Users .pdf
Mastering Windows 7 A Comprehensive Guide for Power Users .pdfMastering Windows 7 A Comprehensive Guide for Power Users .pdf
Mastering Windows 7 A Comprehensive Guide for Power Users .pdf
 
Breaking the Code : A Guide to WhatsApp Business API.pdf
Breaking the Code : A Guide to WhatsApp Business API.pdfBreaking the Code : A Guide to WhatsApp Business API.pdf
Breaking the Code : A Guide to WhatsApp Business API.pdf
 
top nidhi software solution freedownload
top nidhi software solution freedownloadtop nidhi software solution freedownload
top nidhi software solution freedownload
 
Gamify Your Mind; The Secret Sauce to Delivering Success, Continuously Improv...
Gamify Your Mind; The Secret Sauce to Delivering Success, Continuously Improv...Gamify Your Mind; The Secret Sauce to Delivering Success, Continuously Improv...
Gamify Your Mind; The Secret Sauce to Delivering Success, Continuously Improv...
 
Facemoji Keyboard released its 2023 State of Emoji report, outlining the most...
Facemoji Keyboard released its 2023 State of Emoji report, outlining the most...Facemoji Keyboard released its 2023 State of Emoji report, outlining the most...
Facemoji Keyboard released its 2023 State of Emoji report, outlining the most...
 
Corporate Management | Session 3 of 3 | Tendenci AMS
Corporate Management | Session 3 of 3 | Tendenci AMSCorporate Management | Session 3 of 3 | Tendenci AMS
Corporate Management | Session 3 of 3 | Tendenci AMS
 
Crafting the Perfect Measurement Sheet with PLM Integration
Crafting the Perfect Measurement Sheet with PLM IntegrationCrafting the Perfect Measurement Sheet with PLM Integration
Crafting the Perfect Measurement Sheet with PLM Integration
 
Field Employee Tracking System| MiTrack App| Best Employee Tracking Solution|...
Field Employee Tracking System| MiTrack App| Best Employee Tracking Solution|...Field Employee Tracking System| MiTrack App| Best Employee Tracking Solution|...
Field Employee Tracking System| MiTrack App| Best Employee Tracking Solution|...
 
Beyond Event Sourcing - Embracing CRUD for Wix Platform - Java.IL
Beyond Event Sourcing - Embracing CRUD for Wix Platform - Java.ILBeyond Event Sourcing - Embracing CRUD for Wix Platform - Java.IL
Beyond Event Sourcing - Embracing CRUD for Wix Platform - Java.IL
 
TROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERROR
TROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERRORTROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERROR
TROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERROR
 
iGaming Platform & Lottery Solutions by Skilrock
iGaming Platform & Lottery Solutions by SkilrockiGaming Platform & Lottery Solutions by Skilrock
iGaming Platform & Lottery Solutions by Skilrock
 
Prosigns: Transforming Business with Tailored Technology Solutions
Prosigns: Transforming Business with Tailored Technology SolutionsProsigns: Transforming Business with Tailored Technology Solutions
Prosigns: Transforming Business with Tailored Technology Solutions
 
How Does XfilesPro Ensure Security While Sharing Documents in Salesforce?
How Does XfilesPro Ensure Security While Sharing Documents in Salesforce?How Does XfilesPro Ensure Security While Sharing Documents in Salesforce?
How Does XfilesPro Ensure Security While Sharing Documents in Salesforce?
 
Designing for Privacy in Amazon Web Services
Designing for Privacy in Amazon Web ServicesDesigning for Privacy in Amazon Web Services
Designing for Privacy in Amazon Web Services
 
Advanced Flow Concepts Every Developer Should Know
Advanced Flow Concepts Every Developer Should KnowAdvanced Flow Concepts Every Developer Should Know
Advanced Flow Concepts Every Developer Should Know
 
Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...
Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...
Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...
 
AI/ML Infra Meetup | Improve Speed and GPU Utilization for Model Training & S...
AI/ML Infra Meetup | Improve Speed and GPU Utilization for Model Training & S...AI/ML Infra Meetup | Improve Speed and GPU Utilization for Model Training & S...
AI/ML Infra Meetup | Improve Speed and GPU Utilization for Model Training & S...
 
De mooiste recreatieve routes ontdekken met RouteYou en FME
De mooiste recreatieve routes ontdekken met RouteYou en FMEDe mooiste recreatieve routes ontdekken met RouteYou en FME
De mooiste recreatieve routes ontdekken met RouteYou en FME
 
Accelerate Enterprise Software Engineering with Platformless
Accelerate Enterprise Software Engineering with PlatformlessAccelerate Enterprise Software Engineering with Platformless
Accelerate Enterprise Software Engineering with Platformless
 

The Art and Science of Shipping Ember Apps

  • 1. 8/6/14 THE ART AND SCIENCE OF SHIPPING SINGLE PAGE APPS WITH EMBER.JS UX DEVELOPMENT at frog
  • 3.
  • 4.
  • 6.
  • 7. THE ART & SCIENCE OF SHIPPING SINGLE PAGE APPS WITH EMBER.JS
  • 9.
  • 10. 2007
  • 11.
  • 12.
  • 13. ! WHY? ! ! “YOU HAVE TO KNOW THE PAST TO UNDERSTAND THE PRESENT.” ! - DR. CARL SAGAN ! "STUDY THE PAST IF YOU WOULD DEFINE THE FUTURE...." ! - CONFUCIUS ! ! ! ! !
  • 15. App Server EARLY SPA IMPLEMENTATION 15 Container App HTML5/CSS3 Web Framework HTML5/CSS3/JavaScript Data Services JSON/XML Render Engine JavaScript DOM creation && String templates Gadget App iFrame initial load XHR RESPONSE -JSON MARKUP FORMAT XHR REQUEST -JSON ACTION OBJECT Gadget App iFrame Gadget App iFrame REQ PARAMs Iframe Refresh
  • 16.
  • 17.
  • 18. BACK IN THE DAY … A NAIVE IMPLEMENTATION ! ! SEGREGATED DESIGN TEAM HANDED OFF PHOTOSHOP COMPS ! ARCHITECTED SERVER IMPLEMENTATION FIRST ! LACK OF CONVENTIONS AND DEVELOPER ERGONOMICS ! YUI MODULE PATTERN PSEUDO CLASSICAL INHERITANCE ! JSON MARK UP LANGUAGE CUSTOM RENDER ENGINE ! HTML STRINGS AND VARIABLES DOM CREATION ! CONTINUATION PASSING AND CALLBACK HELL ! IFRAMES AND GADGET SPEC ! ! ! ! ! ! !
  • 19. App Server INITIAL LOAD 19 Container App HTML5/CSS3 Web Framework HTML5/CSS3/JavaScript Data Services JSON/XML Render Engine JavaScript DOM creation && String templates Gadget App 1 iFrame initial load Gadget App 2 iFrame Gadget App 3 iFrame REQ PARAMs Iframe Refresh
  • 20. INITIAL LOAD 20 Container App HTML5/CSS3 Web Framework HTML5/CSS3/JavaScript Render Engine JavaScript DOM creation && String templates initial load
  • 21. INITIAL LOAD 21 Container App HTML5/CSS3 Web Framework HTML5/CSS3/JavaScript Render Engine JavaScript DOM creation && String templates initial load { "root": “#portal", "childrenType": "Portal", "type": "ClientCommandObject", "children": [{ "childrenType": "TabContainer", "type": "Portal", "children": [{ "childrenType": "TabPage", "type": "TabContainer", "children": [{ "children": [{ "childrenType": "Gadget", "type": "Column", "children": [{ "gadgetType": "MyAccounts", "gadgetContentType": { "type": "url" } }, { "gadgetType": "EntOffersMlp", "gadgetContentType": { "type": "url" } }, { "gadgetType": "SpendingPlan", "gadgetContentType": { "type": "url" } }, { "gadgetType": "ImcoStorefront", "gadgetContentType": { "type": "url" } },
  • 22. INITIAL LOAD 22 Container App HTML5/CSS3 Web Framework HTML5/CSS3/JavaScript Render Engine JavaScript DOM creation && String templates initial load Main.objects.renderObject(rootEl, configHash);
  • 23. INITIAL LOAD 23 Container App HTML5/CSS3 Web Framework HTML5/CSS3/JavaScript Render Engine JavaScript DOM creation && String templates initial load Main.objects.renderObject = function(root, obj){ this.rootObj = root; // here you make the call to a function to build out your proper div, // this will also append it to the root ! var currentObject = this.constructLayoutObject(this.rootObj, obj); if(obj.children == null || obj.children.length == 0){ return; } else{ // render the branches of the object tree to the root by a recursive call var i; for(i=0; i < obj.children.length; i++){ this.renderObject(currentObject, obj.children[i]); } } };
  • 24. INITIAL LOAD 24 Container App HTML5/CSS3 Web Framework HTML5/CSS3/JavaScript Render Engine JavaScript DOM creation && String templates initial load Main.createNode: function(type, id, classNames) { var node = document.createElement(type); node.id = id; if (typeof classNames === 'string' ) { node.className = classNames; } else if (typeof classNames === 'object' ){ var str = classNames.toString(); var classString=str.replace(/,/g,' '); node.className = classString; } return node; }
  • 25. INITIAL LOAD 25 Container App HTML5/CSS3 Web Framework HTML5/CSS3/JavaScript Render Engine JavaScript DOM creation && String templates initial load ! gadgets.Gadget.prototype.getContent = function(continuation) { gadgets.callAsyncAndJoin( [this.getTitleBarContent, this.getUserPrefsDialogContent, this.getMainContent], function(results) {continuation(results.join(''));}, this); }; ! gadgets.Gadget.prototype.render = function(chrome) { if (chrome) { this.getContent(function(content) { chrome.innerHTML = content; }); } }; !
  • 26. App Server LOADED 26 Container App HTML5/CSS3 Web Framework HTML5/CSS3/JavaScript Data Services JSON/XML Render Engine JavaScript DOM creation && String templates Gadget App 1 iFrame Gadget App 2 iFrame Gadget App 3 iFrame REQ PARAMs Iframe Refresh
  • 27. POST LOADED 27 Container App HTML5/CSS3 Web Framework HTML5/CSS3/JavaScript Render Engine JavaScript DOM creation && String templates DRAG N’ DROP EVENT FIRES! Gadget App 1 iFrame Gadget App 2 iFrame Gadget App 3 iFrame REQ PARAMs Iframe Refresh
  • 28. POST LOADED 28 Container App HTML5/CSS3 Web Framework HTML5/CSS3/JavaScript Render Engine JavaScript DOM creation && String templates Gadget App 1 iFrame Gadget App 2 iFrame Gadget App 3 iFrame REQ PARAMs Iframe Refresh x
  • 29. POST LOADED 29 Container App HTML5/CSS3 Web Framework HTML5/CSS3/JavaScript Render Engine JavaScript DOM creation && String templates Main.moveGadget = function(obj) { var serviceUrlConfigObject = obj; serviceUrlConfigObject.position = (obj.position !== undefined)?obj.position:0; serviceUrlConfigObject.action = "moveObject"; serviceUrlConfigObject.version = 1; Main.services.takeAction('handleMoveGadget' , serviceUrlConfigObject); }; REQ PARAMs Iframe Refresh Gadget App 1 iFrame Gadget App 2 iFrame Gadget App 3 iFrame x
  • 30. POST LOADED 30 Container App HTML5/CSS3 Web Framework HTML5/CSS3/JavaScript Render Engine JavaScript DOM creation && String templates { action:”moveGadget", version:1, category:category, order:order }; XHR REQUEST -JSON ACTION OBJECT Gadget App 1 iFrame Gadget App 2 iFrame Gadget App 3 iFrame x REQ PARAMs Iframe Refresh
  • 31. REFRESH 31 Container App HTML5/CSS3 Web Framework HTML5/CSS3/JavaScript Render Engine JavaScript DOM creation && String templates { "root": “#portal", "childrenType": "Portal", "type": "ClientCommandObject", "children": [{ "childrenType": "TabContainer", "type": "Portal", "children": [{ "childrenType": "TabPage", "type": "TabContainer", "children": [{ "children": [{ "childrenType": "Gadget", "type": "Column", "children": [{ "gadgetType": "MyAccounts", "gadgetContentType": { "type": "url" } }, { "gadgetType": "EntOffersMlp", "gadgetContentType": { "type": "url" } }, { "gadgetType": "SpendingPlan", "gadgetContentType": { "type": "url" } }, { "gadgetType": "ImcoStorefront", "gadgetContentType": { "type": "url" } }, XHR RESPONSE -JSON MARKUP FORMAT Gadget App 1 iFrame Gadget App 2 iFrame Gadget App 3 iFrame x REQ PARAMs Iframe Refresh
  • 32. App Server LOADED 32 Container App HTML5/CSS3 Web Framework HTML5/CSS3/JavaScript Data Services JSON/XML Render Engine JavaScript DOM creation && String templates Gadget App 1 iFrame Gadget App 2 iFrame Gadget App 3 iFrame REQ PARAMs Iframe Refresh MoveGadget ChangePage OpenPanel AddGadget DeleteGadget etc.
  • 33. WE REALLY NEED RAILS IN THE BROWSER!
  • 34.
  • 35.
  • 36. 2014
  • 37. EMBER 37 Views HTML5/CSS3 Web Framework HTML5/CSS3/JavaScript Ember.App JavaScript Ember Data JavaScript ROUTER JavaScript Local Storage JavaScript initial load XHR -JSON WebSocket TEMPLATES .hbs App Server Data Services JSON/XML Models JavaScript Controllers JavaScript Backburner JavaScript Components JavaScript present
  • 38.
  • 39. NxGEN: THE NEW S&P CAPITAL IQ
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47. Working with the S&P labs team we sketched and visualized 5 key concepts. One of the key concepts was a way to analyze and view portfolios through different lenses.
  • 48. BACK IN THE DAY … A NAIVE IMPLEMENTATION ! ! SEGREGATED DESIGN TEAM HANDED OFF PHOTOSHOP COMPS ! ARCHITECTED SERVER IMPLEMENTATION FIRST ! LACK OF CONVENTIONS AND DEVELOPER ERGONOMICS ! YUI MODULE PATTERN PSEUDO CLASSICAL INHERITANCE ! JSON MARK UP LANGUAGE CUSTOM RENDER ENGINE ! HTML STRINGS AND VARIABLES DOM CREATION ! CONTINUATION PASSING AND CALLBACK HELL ! IFRAMES AND GADGET SPEC ! ! ! ! ! ! !
  • 49. PRESENT AND FUTURE ! DESIGN WITH CODE ! WORK FRONT TO BACK ! THE EMBER WAY ! THE EMBER OBJECT MODEL ! EMBER RUN LOOP AND BACKBURNER ! JS TEMPLATES W/ HANDLEBARS / HTMLBARS ! PROMISES AND THE ASYNC ROUTER ! WEB COMPONENTS ! ! ! ! ! ! !
  • 54.
  • 56.
  • 57. BACK END TEAM RAPID DEV 57 Early Design: HTML, Diagram Controllers URL Driven: State Manager and Routes First Populate the Controllers with Dummy Data Models w/ Fixtures FixtureAdapter FRONT END TEAM Models w/ RESTAdapter Build Server-Side Routes/Endpoints Serialization and Formatting JSON Remote Data Store and DB Sync ! ! FixtureAdapter RESTAdapter
  • 58. RAPID DEV REST ADAPTER TEMPLATES FIXTURE ADAPTER ROUTER ROUTE HANDLERS CONTROLLERS VIEWS/COMPONENTS MODELS SERVICES (API DESIGN) MVC, SPA (Bootstrap Object) SERVICES (IMPLEMENTATION) FRONT END DEVELOPMENT WEB/SERVICES DEVELOPMENT D E P L O Y C O N C E P T U A L
  • 60. ADAPTERS 60 App.ApplicationAdapter = DS.FixtureAdapter.extend({ namespace: 'rocknrollcall' }); ! App.ApplicationAdapter = DS.LSAdapter.extend({ namespace: 'rocknrollcall' }); ! App.ActivityAdapter = DS.LSAdapter.extend({ namespace: 'rocknrollcall' }); ! App.ApplicationAdapter = DS.RESTAdapter.extend({ namespace: 'rocknrollcall' });
  • 61. NxGEN: THE NEW S&P CAPITAL IQ
  • 63. EMBER APP KIT 63 { "name": "app-kit", "namespace": "appkit", "APIMethod": "stub", …
  • 64. ROUTES.JS 64 module.exports = function(server) { ! // Create an API namespace, so that the root does not // have to be repeated for each end point. server.namespace("/api", function() { ! // Return fixture data for "/api/activities" server.get("/activities", function(req, res) { var activities = [ ]; }; res.send(activities); }); }); };
  • 65. EMBER APP KIT 65 { "name": "app-kit", "namespace": "appkit", "APIMethod": "stub", … ! { "name": "app-kit", "namespace": "appkit", "APIMethod": “proxy”, "proxyURL": "http://whatever.api:3232", ...
  • 67.
  • 68. ! ! FRIENDS OR FOES ACTIVE GENERATION ! NAMING CONVENTIONS ! !
  • 70. EMBER APPLICATION 70 App = Ember.Application.create({ ! ENV.LOG_MODULE_RESOLVER = true; ENV.APP.LOG_RESOLVER = true; ENV.APP.LOG_ACTIVE_GENERATION = true; ENV.APP.LOG_MODULE_RESOLVER = true; ENV.APP.LOG_TRANSITIONS = true; ENV.APP.LOG_TRANSITIONS_INTERNAL = true; ENV.APP.LOG_VIEW_LOOKUPS = true; ! });
  • 76. YUI2 76 YAHOO.namespace(‘App’); ! App.BaseClass = function(){ method: function(){} }; ! App.Class = function(){ App.BaseClass.call(this); }; ! App.Class.inherits(App.BaseClass); ! App.Class.prototype.method = function(){ ! }; 2007
  • 77. var object = new Base; ! object.extend({ value: "some data”, ! method: function() { alert("Hello World!"); } ! }); ! object.method(); ! // ==> Hello World! BASE2 77 2007
  • 78. EMBER OBJECT 78 App.DefaultPlayer = Em.Object.extend({ ! init: function () { this.set('imgProfilePrefix', 'default_'); }, ! name: “Steve", ! imgName: function (imgType) { return this.get('imgProfilePrefix') + this.get('name').split(' ').join('_').toLowerCase() + this.get('imgProfileSuffix') + '.' + imgType; ! } ! });
  • 79. GETTERS AND SETTERS 79 App.DefaultPlayer = Em.Object.extend({ name: “Steve" }); ! var steve = App.DefaultPlayer.create({}); ! steve.set(‘name’ , ‘Stephen’); ! steve.get(‘name’); // Stephen
  • 81. SUPER() 81 App.DefaultPlayer = Em.Object.extend({ init: function () { this.set('imgProfilePrefix', 'default_'); this.set('imgProfileSuffix', '_profile'); } }); ! App.Player = App.DefaultPlayer.extend({ init: function () { this._super(); this.set('imgProfilePrefix', 'player_'); } });
  • 82. COMPUTED PROPERTIES 82 App.DefaultPlayer = Ember.Object.extend({ … name: "Steve", baseDir: "/images", imgName: function(){ return this.get('imgProfilePrefix') + this.get('name').split(' ').join('_').toLowerCase() + this.get('imgProfileSuffix') + '.png'; }, imgPath: function(){ return this.get('baseDir') + '/profile/' + this.imgName(); }.property('baseDir', 'imgName') });
  • 83. OBSERVERS 83 App.DefaultPlayer = Ember.Object.extend({ … onlineStatusChanged: function(){ console.log('onlineStatusChanged to: ' + this.get('isOnline')); }.observes('isOnline').on('init') }); ! var steve = App.DefaultPlayer.create({ 'isOnline': true }); // onlineStatusChanged to true ! steve.set('isOnline', false); // onlineStatusChanged to false
  • 84. BINDINGS 84 App.DefaultPlayer = Ember.Object.extend({ … name: "Steve", baseDir: "/images", imgName: function(){ return this.get('imgProfilePrefix') + this.get('name').split(' ').join('_').toLowerCase() + this.get('imgProfileSuffix') + '.png'; }, imgPath: function(){ return this.get('baseDir') + '/profile/' + this.imgName(); }.property('baseDir', 'imgName') });
  • 85. EMBER RUN LOOP || BACKBURNER.JS
  • 86. POST LOADED 86 Container App HTML5/CSS3 Web Framework HTML5/CSS3/JavaScript Render Engine JavaScript DOM creation && String templates Gadget App 1 iFrame Gadget App 2 iFrame Gadget App 3 iFrame REQ PARAMs Iframe Refresh 2007
  • 87. POST LOADED 87 Container App HTML5/CSS3 Web Framework HTML5/CSS3/JavaScript Render Engine JavaScript DOM creation && String templates { action:”moveGadget", version:1, category:category, order:order }; XHR REQUEST -JSON ACTION OBJECT Gadget App 1 iFrame Gadget App 2 iFrame Gadget App 3 iFrame x REQ PARAMs Iframe Refresh DRAG N’ DROP EVENT FIRES! 2007
  • 88. POST LOADED 88 Container App HTML5/CSS3 Web Framework HTML5/CSS3/JavaScript Render Engine JavaScript DOM creation && String templates { action:”moveGadget", version:1, category:category, order:order }; XHR REQUEST -JSON ACTION OBJECT Gadget App 1 iFrame Gadget App 2 iFrame Gadget App 3 iFrame x REQ PARAMs Iframe Refresh x { action:”moveGadget", version:1, category:category, order:order }; XHR REQUEST -JSON ACTION OBJECT 2007
  • 89. RUN LOOP 89 ! BBone.DisplayView = Backbone.View.extend({ ! initialize: function () { this.listenTo(this.model, 'change', this.render); }, render: function() { console.log(‘render’); } }); ! // render model.set('firstName', 'Erik'); // render again model.set('lastName', 'Bryn'); ! !
  • 91. RUN LOOP 91 ! BBone.DisplayView = Backbone.View.extend({ initialize: function () { this.listenTo(this.model, 'change', this.render); }, render: function() { backburner.deferOnce('render', this, this.actuallyRender); }, actuallyRender: function() { // do our DOM manipulations here. will only be called once. } }); backburner.run(function() { model.set('firstName', 'Erik'); model.set('lastName', 'Bryn'); }); !
  • 92. ! EMBER.RUN.QUEUES ! FLUSHING ROUTER TRANSITIONS ! ["SYNC", “ACTIONS", "ROUTERTRANSITIONS", "RENDER", "AFTERRENDER", "DESTROY"]
  • 96. DOM 96 Container App HTML5/CSS3 Web Framework HTML5/CSS3/JavaScript Render Engine JavaScript DOM creation && String templates JSON MARKUP LANGUAGE Main.createNode: function(type, id, classNames) { var node = document.createElement(type); node.id = id; if (typeof classNames === 'string' ) { node.className = classNames; } else if (typeof classNames === 'object' ){ var str = classNames.toString(); var classString=str.replace(/,/g,' '); node.className = classString; } return node; } 2007
  • 97. DOM VS INNERHTML 97 <script type="text/x-handlebars" data-template- name=“application"> ! <!-- template code here --> ! </script> 2007
  • 99. INNERHTML 99 Container App HTML5/CSS3 Web Framework HTML5/CSS3/JavaScript Render Engine JavaScript DOM creation && String templates gadgets.Gadget.prototype.render = function(chrome) { if (chrome) { this.getContent(function(content) { chrome.innerHTML = content; }); } }; ! 2007 JSON MARKUP LANGUAGE
  • 100. JS TEMPLATES WITH HANDLEBARS ! Ember.TEMPLATES
  • 101. HANDLEBARS 101 <div {{bind-attr class=“myClass"}}> {{myValue}} </div> Compiled JS Functions ! Em.TEMPLATES Handlebars Compiler Emits String !     //This  is  how  handlebars  works   var  output  =  "";   output.push("<div  class="");   output.push("<script  type='text/x-­‐placeholder'  id='start-­‐1'></script>");   //  insert  the  value  of  myClass   output.push("<script  type='text/x-­‐placeholder'  id='end-­‐1'></script>");   output.push("">");   output.push("<script  type='text/x-­‐placeholder'  id='start-­‐2'></script>");   //  insert  the  value  of  myValue   output.push("<script  type='text/x-­‐placeholder'  id='end-­‐2'></script>");   output.push("</div>"); Output string innerHTML
  • 102. HANDLEBARS 102 <script type="text/x-handlebars" data-template- name=“application"> <!-- template code here --> </script> grunt.initConfig({ yeoman: yeomanConfig, watch: { emberTemplates: { files: '<%= yeoman.app %>/templates/**/*.hbs', tasks: ['emberTemplates', 'livereload'] } } });
  • 103. VARIABLES 103 {{App.applicationName}} <ul class="navbar artists”> {{#each item in navbar-items}} {{#if item.isAccessible}} {{#each label in items.labels}} <li> {{#linkTo ‘label’ label.id}}{{label.title}}{{/linkTo}} </li> {{/each}} {{else}} <li> <a {{bind-attr href=‘item.fullAddress’}}> {{item.name}}</a> </li> {{/if}} {{/each}} </ul>
  • 104. MINIMAL LOGIC 104 {{App.applicationName}} <ul class="navbar artists”> {{#each item in navbar-items}} {{#if item.isAccessible}} {{#each label in items.labels}} <li> {{#linkTo ‘label’ label.id}}{{label.title}}{{/linkTo}} </li> {{/each}} {{else}} <li> <a {{bind-attr href=‘item.fullAddress’}}> {{item.name}}</a> </li> {{/if}} {{/each}} </ul>
  • 105. LINKS 105 {{App.applicationName}} <ul class="navbar artists”> {{#each item in navbar-items}} {{#if item.isAccessible}} {{#each label in items.labels}} <li> {{#linkTo ‘label’ label.id}}{{label.title}}{{/linkTo}} </li> {{/each}} {{else}} <li> <a {{bind-attr href=‘item.fullAddress’}}> {{item.name}}</a> </li> {{/if}} {{/each}} </ul>
  • 106. LISTS 106 {{App.applicationName}} <ul class="navbar artists”> {{#each item in navbar-items}} {{#if item.isAccessible}} {{#each label in item.labels}} <li> {{#linkTo ‘label’ label.id}}{{label.title}}{{/linkTo}} </li> {{/each}} {{else}} <li> <a {{bind-attr href=‘item.fullAddress’}}> {{item.name}}</a> </li> {{/if}} {{/each}} </ul>
  • 107. BOUND ATTRIBUTES 107 {{App.applicationName}} <ul class="navbar artists”> {{#each item in navbar-items}} {{#if item.isAccessible}} {{#each label in items.labels}} <li> {{#linkTo ‘label’ label.id}}{{label.title}}{{/linkTo}} </li> {{/each}} {{else}} <li> <a {{bind-attr href=‘item.fullAddress’}}> {{item.name}}</a> </li> {{/if}} {{/each}} </ul>
  • 109. ! ! HTMLBARS OVER HANDLEBARS PERFORMANCE ! BIND-ATTR GONE ! METAMORPH GONE ! LOGIC IN TEMPLATES ! !
  • 110. HTMLBARS 110 <div   class=“{{myClass}}”>   {{myValue}}   </div> Compiled JS Functions ! Em.TEMPLATES HTMLBars Compiler Emits DOM elements var  output  =  dom.createDocumentFragment();   var  div  =  dom.createElement('div');   dom.RESOLVE_ATTR(context,  div,  'class',  'myClass');   var  text  =  dom.createTextNode();   dom.RESOLVE(context,  text,  'textContent',  'myValue');   div.appendChild(text);   output.appendChild(div); <div  class="{{myClass}}">{{myValue}}</div>
  • 111. BOUND ATTRIBUTES 111 {{App.applicationName}} <ul class="navbar artists”> {{#each item in navbar-items}} {{#if item.isAccessible}} {{#each label in items.labels}} <li> {{#linkTo ‘label’ label.id}}{{label.title}}{{/linkTo}} </li> {{/each}} {{else}} <li> <a {{bind-attr href=‘item.fullAddress’}}> {{item.name}}</a> </li> {{/if}} {{/each}} </ul>
  • 112. NO MORE BIND-ATTR 112 {{App.applicationName}} <ul class="navbar artists”> {{#each item in navbar-items}} {{#if item.isAccessible}} {{#each label in items.labels}} <li> {{#linkTo ‘label’ label.id}}{{label.title}}{{/linkTo}} </li> {{/each}} {{else}} <li> <a href=“{{fullAddress}}”> {{item.name}}</a> </li> {{/if}} {{/each}} </ul>
  • 113. LOGIC-LESS 113 {{App.applicationName}} <ul class="navbar artists”> {{#each item in navbar-items}} {{#if item.isAccessible}} {{#each label in items.labels}} <li> {{#linkTo ‘label’ label.id}}{{label.title}}{{/linkTo}} </li> {{/each}} {{else}} <li> <a href=“{{fullAddress}}”> {{item.name}}</a> </li> {{/if}} {{/each}} </ul>
  • 114. LOGIC 114 {{App.applicationName}} <ul class="navbar artists”> {{#each item in navbar-items}} {{#if (item.type === ‘sidenavbar-item’) }} {{#each label in items.labels}} <li> {{#linkTo ‘label’ label.id}}{{label.title}}{{/linkTo}} </li> {{/each}} {{else}} <li> <a href=“{{fullAddress}}”> {{item.name}}</a> </li> {{/if}} {{/each}} </ul>
  • 117.
  • 118. PROMISES AND THE ASYNC ROUTER
  • 120. RSVP 120 var p = new RSVP.Promise(function(resolve, reject) { // succeed resolve(value); // or reject reject(error); }); ! p.then(function(value) { // success }, function(value) { // failure });
  • 121. CONTINUATION 121 Container App HTML5/CSS3 Web Framework HTML5/CSS3/JavaScript Render Engine JavaScript DOM creation && String templates ! gadgets.Gadget.prototype.getContent = function(continuation) { gadgets.callAsyncAndJoin( [this.getTitleBarContent, this.getUserPrefsDialogContent, this.getMainContent], function(results) {continuation(results.join(''));}, this); }; ! gadgets.Gadget.prototype.render = function(chrome) { if (chrome) { this.getContent(function(content) { chrome.innerHTML = content; }); } }; ! 2007
  • 122. CONTINUATION 122 ! gadgets.Gadget.prototype.getContent = function(continuation) { gadgets.callAsyncAndJoin( [this.getTitleBarContent, this.getUserPrefsDialogContent, this.getMainContent], function(results) {continuation(results.join(''));}, this); }; ! gadgets.Gadget.prototype.render = function(chrome) { if (chrome) { this.getContent(function(content) { chrome.innerHTML = content; }); } }; ! 2007
  • 123. XHR RESPONSE 123 Container App HTML5/CSS3 Web Framework HTML5/CSS3/JavaScript Render Engine JavaScript DOM creation && String templates { "root": “#portal", "childrenType": "Portal", "type": "ClientCommandObject", "children": [{ "childrenType": "TabContainer", "type": "Portal", "children": [{ "childrenType": "TabPage", "type": "TabContainer", "children": [{ "children": [{ "childrenType": "Gadget", "type": "Column", "children": [{ "gadgetType": "MyAccounts", "gadgetContentType": { "type": "url" } }, { "gadgetType": "EntOffersMlp", "gadgetContentType": { "type": "url" } }, { "gadgetType": "SpendingPlan", "gadgetContentType": { "type": "url" } }, { "gadgetType": "ImcoStorefront", "gadgetContentType": { "type": "url" } }, XHR RESPONSE -JSON MARKUP FORMAT Gadget App 1 iFrame Gadget App 2 iFrame Gadget App 3 iFrame x REQ PARAMs Iframe Refresh 2007
  • 124. SUCCESS, FAILURE 124 Main.YUIConnectionManager.callback = { success: function(o) { try { var data = YAHOO.lang.JSON.parse(o.responseText); } catch (e) { Main.debug(err + " - Invalid data”); } }, failure: function(o) { } }; 2007
  • 125. ROUTE HANDLERS 125 App.ArtistRoute = Ember.Route.extend({ model: function(params) { ! XHR( "some URL” , {"id":params.enid}, function callback(response){ // handle response }); ! } });
  • 126. PROMISES 126 RSVP.all([ afunction(), another(), yetAnother()]) ! .then(function() { ! console.log("They're all finished, success is ours!”); ! }, function() { ! console.error("One or more FAILED!”); });
  • 127. PROMISES 127 var promises = { posts: getJSON("/posts.json"), users: getJSON("/users.json") }; ! RSVP.hash(promises).then(function(results) { console.log(results.users) // print the users.json results console.log(results.posts) // print the posts.json results });
  • 128. PRESENT AND FUTURE ! DESIGN WITH CODE ! WORK FRONT TO BACK ! THE EMBER WAY ! THE EMBER OBJECT MODEL ! EMBER RUN LOOP AND BACKBURNER ! JS TEMPLATES W/ HANDLEBARS / HTMLBARS ! PROMISES AND THE ASYNC ROUTER ! WEB COMPONENTS ! ! ! ! ! ! !
  • 130. IFRAMES ! TRADITIONAL WEB DEVELOPERS CAN ADD CONTENT ! SANDBOXED CONTENT / CAN LOAD FROM PROXIES ! POST MESSAGE API HAS EVOLVED / CONTAINER CAN CREAT AN INTERFACE ! DONT NEED TO LEARN CONTAINER IMPLEMENTATION ! ! ! ! ! ! ! ! ! ! ! ! !
  • 132. OH WAIT, ONE MORE THING. ! - ERIK BRYN, EMBER CONF 2014