the art and science of shipping ember apps

134
8/6/14 THE ART AND SCIENCE OF SHIPPING SINGLE PAGE APPS WITH EMBER.JS UX DEVELOPMENT at frog

Upload: jesse-cravens

Post on 13-May-2015

297 views

Category:

Software


2 download

DESCRIPTION

As an alternative to other popular client MVC solutions like Backbone.js and Angular.js, Ember.js differs in that it provides 'Rails-like' defaults by convention to common coding patterns, intelligent memory management, built-in integration testing, and numerous, next generation client side persistence solutions. Join O'Reilly author, Jesse Cravens, as he presents information from his new book: O'Reilly's 'Building Web Apps with Ember.js’ as he takes the audience through the construction of the RocknRollCall demo application. Construct a workflow using the latest in JavaScript build and package management solutions. Use Handlebars and Ember templates.

TRANSCRIPT

Page 1: The Art and Science of Shipping Ember Apps

8/6/14

THE ART AND SCIENCE OF SHIPPING SINGLE PAGE APPS WITH EMBER.JS

UX DEVELOPMENT at frog

Page 2: The Art and Science of Shipping Ember Apps

@jdcravens github.com/jessecravens jessecravens.com principal web architect | frog Austin

Page 3: The Art and Science of Shipping Ember Apps
Page 4: The Art and Science of Shipping Ember Apps
Page 5: The Art and Science of Shipping Ember Apps

ART & SCIENCE

Page 6: The Art and Science of Shipping Ember Apps
Page 7: The Art and Science of Shipping Ember Apps

THE ART & SCIENCE OF SHIPPING SINGLE PAGE APPS WITH EMBER.JS

Page 8: The Art and Science of Shipping Ember Apps

2006

Page 9: The Art and Science of Shipping Ember Apps
Page 10: The Art and Science of Shipping Ember Apps

2007

Page 11: The Art and Science of Shipping Ember Apps
Page 12: The Art and Science of Shipping Ember Apps
Page 13: The Art and Science of Shipping Ember Apps

!WHY? !!“YOU HAVE TO KNOW THE PAST TO UNDERSTAND THE PRESENT.”

!- DR. CARL SAGAN

!"STUDY THE PAST IF YOU WOULD DEFINE THE FUTURE...."

!- CONFUCIUS

!!

!!

!

Page 14: The Art and Science of Shipping Ember Apps

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

Page 15: The Art and Science of Shipping Ember Apps

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

Page 16: The Art and Science of Shipping Ember Apps
Page 17: The Art and Science of Shipping Ember Apps
Page 18: The Art and Science of Shipping Ember Apps

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 !!!!

!!

!

Page 19: The Art and Science of Shipping Ember Apps

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

Page 20: The Art and Science of Shipping Ember Apps

INITIAL LOAD

20

Container App HTML5/CSS3

Web Framework HTML5/CSS3/JavaScript

Render Engine JavaScript DOM creation && String templates

initial load

Page 21: The Art and Science of Shipping Ember Apps

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" } },

Page 22: The Art and Science of Shipping Ember Apps

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);

Page 23: The Art and Science of Shipping Ember Apps

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]); } } };

Page 24: The Art and Science of Shipping Ember Apps

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; }

Page 25: The Art and Science of Shipping Ember Apps

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; }); } }; !

Page 26: The Art and Science of Shipping Ember Apps

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

Page 27: The Art and Science of Shipping Ember Apps

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

Page 28: The Art and Science of Shipping Ember Apps

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

Page 29: The Art and Science of Shipping Ember Apps

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

Page 30: The Art and Science of Shipping Ember Apps

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

Page 31: The Art and Science of Shipping Ember Apps

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

Page 32: The Art and Science of Shipping Ember Apps

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.

Page 33: The Art and Science of Shipping Ember Apps

WE REALLY NEED RAILS IN THE BROWSER!

Page 34: The Art and Science of Shipping Ember Apps
Page 35: The Art and Science of Shipping Ember Apps
Page 36: The Art and Science of Shipping Ember Apps

2014

Page 37: The Art and Science of Shipping Ember Apps

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

Page 38: The Art and Science of Shipping Ember Apps
Page 39: The Art and Science of Shipping Ember Apps

NxGEN: THE NEW S&P CAPITAL IQ

Page 40: The Art and Science of Shipping Ember Apps
Page 41: The Art and Science of Shipping Ember Apps
Page 42: The Art and Science of Shipping Ember Apps
Page 43: The Art and Science of Shipping Ember Apps
Page 44: The Art and Science of Shipping Ember Apps
Page 45: The Art and Science of Shipping Ember Apps
Page 46: The Art and Science of Shipping Ember Apps
Page 47: The Art and Science of Shipping Ember Apps

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.

Page 48: The Art and Science of Shipping Ember Apps

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 !!!!

!!

!

Page 49: The Art and Science of Shipping Ember Apps

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 !!!!

!!

!

Page 50: The Art and Science of Shipping Ember Apps

DESIGN WITH CODE

Page 51: The Art and Science of Shipping Ember Apps

SKETCH ADOBE EDGE REFLOW WEBFLOW MACAW !

Page 52: The Art and Science of Shipping Ember Apps

SKETCH ADOBE EDGE REFLOW WEBFLOW MACAW !

Page 53: The Art and Science of Shipping Ember Apps

CHROME DEV TOOLS !

Page 54: The Art and Science of Shipping Ember Apps
Page 55: The Art and Science of Shipping Ember Apps

WORK FRONT TO BACK

Page 56: The Art and Science of Shipping Ember Apps
Page 57: The Art and Science of Shipping Ember Apps

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

Page 58: The Art and Science of Shipping Ember Apps

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

DEPLOY

CONCEPTUAL

Page 59: The Art and Science of Shipping Ember Apps

EMBER DATA ADAPTERS !

Page 60: The Art and Science of Shipping Ember Apps

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' });

Page 61: The Art and Science of Shipping Ember Apps

NxGEN: THE NEW S&P CAPITAL IQ

Page 62: The Art and Science of Shipping Ember Apps

API STUBS !

Page 63: The Art and Science of Shipping Ember Apps

EMBER APP KIT

63

{ "name": "app-kit", "namespace": "appkit", "APIMethod": "stub", …

Page 64: The Art and Science of Shipping Ember Apps

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); }); }); };

Page 65: The Art and Science of Shipping Ember Apps

EMBER APP KIT

65

{ "name": "app-kit", "namespace": "appkit", "APIMethod": "stub", … !{ "name": "app-kit", "namespace": "appkit", "APIMethod": “proxy”, "proxyURL": "http://whatever.api:3232", ...

Page 66: The Art and Science of Shipping Ember Apps

EMBRACE THE EMBER WAY

Page 67: The Art and Science of Shipping Ember Apps
Page 68: The Art and Science of Shipping Ember Apps

!!FRIENDS OR FOES

ACTIVE GENERATION !

NAMING CONVENTIONS !

!

Page 69: The Art and Science of Shipping Ember Apps

ACTIVE GENERATION

Page 70: The Art and Science of Shipping Ember Apps

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; !});

Page 71: The Art and Science of Shipping Ember Apps

NAMING CONVENTIONS

Page 72: The Art and Science of Shipping Ember Apps

CONVENTIONS

Page 73: The Art and Science of Shipping Ember Apps

NAMING CONVENTIONS

Page 74: The Art and Science of Shipping Ember Apps

CONVENTIONS

Page 75: The Art and Science of Shipping Ember Apps

THE EMBER OBJECT MODEL

Page 76: The Art and Science of Shipping Ember Apps

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

Page 77: The Art and Science of Shipping Ember Apps

var object = new Base; !object.extend({ value: "some data”, ! method: function() { alert("Hello World!"); } !}); !object.method(); !// ==> Hello World!

BASE2

77200

7

Page 78: The Art and Science of Shipping Ember Apps

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; ! } !});

Page 79: The Art and Science of Shipping Ember Apps

GETTERS AND SETTERS

79

App.DefaultPlayer = Em.Object.extend({ name: “Steve" }); !var steve = App.DefaultPlayer.create({}); !steve.set(‘name’ , ‘Stephen’); !steve.get(‘name’); // Stephen

Page 80: The Art and Science of Shipping Ember Apps

INHERITANCE

80

App.DefaultPlayer = Em.Object.extend({}); !App.Player = App.DefaultPlayer.extend({ … });

Page 81: The Art and Science of Shipping Ember Apps

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_'); } });

Page 82: The Art and Science of Shipping Ember Apps

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') });

Page 83: The Art and Science of Shipping Ember Apps

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

Page 84: The Art and Science of Shipping Ember Apps

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') });

Page 85: The Art and Science of Shipping Ember Apps

EMBER RUN LOOP || BACKBURNER.JS

Page 86: The Art and Science of Shipping Ember Apps

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

Page 87: The Art and Science of Shipping Ember Apps

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

Page 88: The Art and Science of Shipping Ember Apps

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

Page 89: The Art and Science of Shipping Ember Apps

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'); !!

Page 90: The Art and Science of Shipping Ember Apps

ACTIONS ARE DEFERRED !

Page 91: The Art and Science of Shipping Ember Apps

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'); }); !

Page 92: The Art and Science of Shipping Ember Apps

!

EMBER.RUN.QUEUES !

FLUSHING ROUTER TRANSITIONS !

["SYNC", “ACTIONS", "ROUTERTRANSITIONS", "RENDER", "AFTERRENDER", "DESTROY"]

Page 93: The Art and Science of Shipping Ember Apps

!

EMBER.RUN.QUEUES !

["SYNC", "ACTIONS", "ROUTERTRANSITIONS", "RENDER", "AFTERRENDER", "DESTROY"]

Page 94: The Art and Science of Shipping Ember Apps

AINT’ THAT FANCY!

Page 95: The Art and Science of Shipping Ember Apps

JS TEMPLATES

Page 96: The Art and Science of Shipping Ember Apps

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

Page 97: The Art and Science of Shipping Ember Apps

DOM VS INNERHTML

97

<script type="text/x-handlebars" data-template-name=“application"> ! <!-- template code here --> !</script>

2007

Page 98: The Art and Science of Shipping Ember Apps

DOM VS INNERHTML

98200

8

Page 99: The Art and Science of Shipping Ember Apps

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

Page 100: The Art and Science of Shipping Ember Apps

JS TEMPLATES WITH HANDLEBARS !

Ember.TEMPLATES

Page 101: The Art and Science of Shipping Ember Apps

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

Page 102: The Art and Science of Shipping Ember Apps

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'] } } });

Page 103: The Art and Science of Shipping Ember Apps

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>

Page 104: The Art and Science of Shipping Ember Apps

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>

Page 105: The Art and Science of Shipping Ember Apps

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>

Page 106: The Art and Science of Shipping Ember Apps

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>

Page 107: The Art and Science of Shipping Ember Apps

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>

Page 108: The Art and Science of Shipping Ember Apps

!

HTMLBARS

Page 109: The Art and Science of Shipping Ember Apps

!!HTMLBARS OVER HANDLEBARS

PERFORMANCE !

BIND-ATTR GONE !

METAMORPH GONE !

LOGIC IN TEMPLATES !

!

Page 110: The Art and Science of Shipping Ember Apps

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>

Page 111: The Art and Science of Shipping Ember Apps

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>

Page 112: The Art and Science of Shipping Ember Apps

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>

Page 113: The Art and Science of Shipping Ember Apps

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>

Page 114: The Art and Science of Shipping Ember Apps

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>

Page 115: The Art and Science of Shipping Ember Apps

HTMLBARS

115

<script type="text/x-handlebars" data-template-name=“application"> ! <!-- template code here --> !</script>

Page 116: The Art and Science of Shipping Ember Apps

METAMORPHS

116

Page 117: The Art and Science of Shipping Ember Apps
Page 118: The Art and Science of Shipping Ember Apps

PROMISES AND THE ASYNC ROUTER

Page 119: The Art and Science of Shipping Ember Apps

!!RSVP

PROMISES/A+ !

ES6 COMPLIANT !

CONVENIENCE METHODS !!!!!

!

Page 120: The Art and Science of Shipping Ember Apps

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 });

Page 121: The Art and Science of Shipping Ember Apps

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; }); } }; ! 200

7

Page 122: The Art and Science of Shipping Ember Apps

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

Page 123: The Art and Science of Shipping Ember Apps

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

Page 124: The Art and Science of Shipping Ember Apps

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

Page 125: The Art and Science of Shipping Ember Apps

ROUTE HANDLERS

125

App.ArtistRoute = Ember.Route.extend({ model: function(params) { ! XHR( "some URL” , {"id":params.enid}, function callback(response){ // handle response }); ! } });

Page 126: The Art and Science of Shipping Ember Apps

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!”); });

Page 127: The Art and Science of Shipping Ember Apps

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 });

Page 128: The Art and Science of Shipping Ember Apps

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 !!!!

!!

!

Page 129: The Art and Science of Shipping Ember Apps

WEB COMPONENTS

Page 130: The Art and Science of Shipping Ember Apps

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 !!!!!!!!!!

!!

!

Page 131: The Art and Science of Shipping Ember Apps

THAT’S NASTY

Page 132: The Art and Science of Shipping Ember Apps

OH WAIT, ONE MORE THING. !

- ERIK BRYN, EMBER CONF 2014

Page 133: The Art and Science of Shipping Ember Apps

THE FUTURE IS NOW

Page 134: The Art and Science of Shipping Ember Apps