SlideShare une entreprise Scribd logo
1  sur  134
Télécharger pour lire hors ligne
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

Contenu connexe

Tendances

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
 

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

Similaire à 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
 

Similaire à 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
 

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

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

Dernier

+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...Health
 
5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdfWave PLM
 
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...harshavardhanraghave
 
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfkalichargn70th171
 
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...OnePlan Solutions
 
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...kellynguyen01
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providermohitmore19
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Modelsaagamshah0812
 
Diamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionDiamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionSolGuruz
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...ICS
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfkalichargn70th171
 
CALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female service
CALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female serviceCALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female service
CALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female serviceanilsa9823
 
A Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxA Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxComplianceQuest1
 
How To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsHow To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsAndolasoft Inc
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comFatema Valibhai
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVshikhaohhpro
 
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️anilsa9823
 
Right Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsRight Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsJhone kinadey
 

Dernier (20)

+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
 
5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf
 
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
 
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
 
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
 
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service provider
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Models
 
Diamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionDiamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with Precision
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
 
CALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female service
CALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female serviceCALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female service
CALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female service
 
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS LiveVip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
 
A Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxA Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docx
 
How To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsHow To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.js
 
Microsoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdfMicrosoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdf
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.com
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTV
 
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️
 
Right Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsRight Money Management App For Your Financial Goals
Right Money Management App For Your Financial Goals
 

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