Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
The Rendering Revolution: Running Apps in the B...
Search
Trek Glowacki
October 24, 2013
Technology
2
450
The Rendering Revolution: Running Apps in the Browser with Ember.js
Trek Glowacki
October 24, 2013
Tweet
Share
More Decks by Trek Glowacki
See All by Trek Glowacki
Documents are not the web
trek
1
240
Beyond Front-end Developer
trek
1
480
UI Patterns and Reuse ~ or ~ Why I Hope We Never Need an Ember.js Widget Library
trek
10
5.9k
applications: a series of states
trek
19
2.1k
Cargo Cults
trek
0
330
Other Decks in Technology
See All in Technology
AI に「学ばせ、調べさせ、作らせる」。Auth0 開発を加速させる7つの実践的アプローチ
scova0731
0
240
ECS_EKS以外の選択肢_ROSA入門_.pdf
masakiokuda
1
130
Oracle Database@AWS:サービス概要のご紹介
oracle4engineer
PRO
2
870
[PR] はじめてのデジタルアイデンティティという本を書きました
ritou
1
800
kintone開発のプラットフォームエンジニアの紹介
cybozuinsideout
PRO
0
510
Keynoteから見るAWSの頭の中
nrinetcom
PRO
1
180
松尾研LLM講座2025 応用編Day3「軽量化」 講義資料
aratako
15
5k
形式手法特論:コンパイラの「正しさ」は証明できるか? #burikaigi / BuriKaigi 2026
ytaka23
16
5.2k
Eight Engineering Unit 紹介資料
sansan33
PRO
0
6.2k
AWSと生成AIで学ぶ!実行計画の読み解き方とSQLチューニングの実践
yakumo
2
450
AI時代のアジャイルチームを目指して ー スクラムというコンフォートゾーンからの脱却 ー / Toward Agile Teams in the Age of AI
takaking22
11
6.4k
国井さんにPurview の話を聞く会
sophiakunii
1
370
Featured
See All Featured
Marketing Yourself as an Engineer | Alaka | Gurzu
gurzu
0
110
How Software Deployment tools have changed in the past 20 years
geshan
0
31k
Ruling the World: When Life Gets Gamed
codingconduct
0
120
End of SEO as We Know It (SMX Advanced Version)
ipullrank
2
3.9k
From Legacy to Launchpad: Building Startup-Ready Communities
dugsong
0
120
The AI Revolution Will Not Be Monopolized: How open-source beats economies of scale, even for LLMs
inesmontani
PRO
3
2.8k
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
141
34k
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
25
1.7k
The B2B funnel & how to create a winning content strategy
katarinadahlin
PRO
0
230
SERP Conf. Vienna - Web Accessibility: Optimizing for Inclusivity and SEO
sarafernandez
1
1.3k
The Invisible Side of Design
smashingmag
302
51k
Prompt Engineering for Job Search
mfonobong
0
140
Transcript
@trek
None
None
None
IE 5 IE 8 IE 7
None
None
None
None
None
None
None
None
None
2003 2005 2009
None
None
None
None
None
None
Why?
None
None
None
None
None
None
None
screen rendering display screen state AFK behavior persistence
screen rendering display screen state AFK behavior persistence client server
screen rendering display screen state AFK behavior persistence client server
APIs Node, Rails
APIs
screen rendering display screen state AFK behavior persistence client server
screen rendering display screen state AFK behavior persistence client server
None
Mobile Cocoa Touch Android SDK Desktop Cocoa .NET Web ?
Mobile Cocoa Touch Android SDK Desktop Cocoa .NET Web
None
None
Router Route Controller View/Template Model/Data
Router Route Controller View/Template Model/Data what is the current context?
how does this encode to a URL?
Router Route Controller View/Template Model/Data What data should I fetch?
What template should I show?
Router Route Controller View/Template Model/Data how do I translate user
interaction in this context into intent (e.g. a "click" into "show me more")? how do I present the data for this context?
Router Route Controller View/Template Model/Data how do I paint to
the screen?
Router Route Controller View/Template Model/Data what is the structure of
my data
Router Route Controller View/Template Model/Data
App = Ember.Application.create(); <!-- application.hbs --> <h1>Welcome to Ember.js</h1> Router
Route Controller View/Template Model/Data
None
App = Ember.Application.create(); App.Router.map(function(){ this.route("about"); this.route("favorites", { path: "/favs" });
}); <!-- application.hbs --> <h1>Welcome to Ember.js</h1> <nav> {{#link-to 'about'}}About{{/link-to}} {{#link-to 'favorites'}}Favorites{{/link-to}} {{outlet}}<!-- filled with child template when you navigate into route --> </nav> <!-- favorites.hbs --> <h2>Favorites<h2> <ul> <li>...</li> <li>...</li> </ul> <!-- about.hbs --> <h2>About<h2>
None
App = Ember.Application.create(); App.Router.map(function(){ this.route("about"); this.route("favorites", { path: "/favs" });
}); <!-- application.hbs --> <h1>Welcome to Ember.js</h1> <nav> {{#link-to 'about'}}About{{/link-to}} {{#link-to 'favorites'}}Favorites{{/link-to}} {{outlet}}<!-- filled with child template when you navigate into route --> </nav> <!-- favorites.hbs --> <h2>Favorites<h2> <ul> <li>...</li> <li>...</li> </ul> <!-- about.hbs --> <h2>About<h2>
App = Ember.Application.create(); App.Router.map(function(){ this.route("about"); this.route("favorites", { path: "/favs" });
}); App.AboutRoute = Ember.Route.extend({ model: function(){ return $.ajax({ url: '/api/currentUser/profile' }); } });
App = Ember.Application.create(); App.Router.map(function(){ this.route("about"); this.route("favorites", { path: "/favs" });
}); App.AboutRoute = Ember.Route.extend({ model: function(){ var self = this; $('#a-loader).show(); $.ajax({ url: '/api/currentUser/profile', success: function(response){ $('#a-loader).hide(); self.renderWithSomeData(response); } }); } });
App = Ember.Application.create(); App.Router.map(function(){ this.route("about"); this.route("favorites", { path: "/favs" });
}); App.AboutRoute = Ember.Route.extend({ model: function(){ return $.ajax({ url: '/api/currentUser/profile' }); } }); { name: 'trek', bio: 'Much shorter than you expect' }
App = Ember.Application.create(); App.Router.map(function(){ this.route("about"); this.route("favorites", { path: "/favs" });
}); <!-- favorites.hbs --> <h2>Favorites<h2> <ul> <li>...</li> <li>...</li> </ul> <!-- about.hbs --> <h2>About<h2> <!-- application.hbs --> <h1>Welcome to Ember.js</h1> <nav> {{#link-to 'about'}}About{{/link-to}} {{#link-to 'favorites'}}Favorites{{/link-to}} {{outlet}}<!-- filled with child template when you navigate into route --> </nav>
App = Ember.Application.create(); App.Router.map(function(){ this.route("about"); this.route("favorites", { path: "/favs" });
}); <!-- favorites.hbs --> <h2>Favorites<h2> <ul> <li>...</li> <li>...</li> </ul> <!-- about.hbs --> <h1>About<h1> <h2>{{name}}<h2> <div class='bio'> {{bio}} </div> <!-- application.hbs --> <h1>Welcome to Ember.js</h1> <nav> {{#link-to 'about'}}About{{/link-to}} {{#link-to 'favorites'}}Favorites{{/link-to}} {{outlet}}<!-- filled with child template when you navigate into route --> </nav>
App = Ember.Application.create(); App.Router.map(function(){ this.route("about"); this.route("favorites", { path: "/favs" });
}); App.FavoritesRoute = Ember.Route.extend({ model: function(){ return $.ajax({ url: '/api/currentUser/favorites' }); } }); [ {"id": 1, "title": "Hoverbike Captains of the SS"}, {"id": 2, "title": "The Terrifying Madness That Lies Beyond"} ]
App = Ember.Application.create(); App.Router.map(function(){ this.route("about"); this.route("favorites", { path: "/favs" });
}); <!-- favorites.hbs --> <h2>Favorites<h2> <ul> <li>...</li> <li>...</li> </ul> <!-- about.hbs --> <h1>About<h1> <h2>{{name}}<h2> <div class='bio'> {{bio}} </div> <!-- application.hbs --> <h1>Welcome to Ember.js</h1> <nav> {{#link-to 'about'}}About{{/link-to}} {{#link-to 'favorites'}}Favorites{{/link-to}} {{outlet}}<!-- filled with child template when you navigate into route --> </nav>
App = Ember.Application.create(); App.Router.map(function(){ this.route("about"); this.route("favorites", { path: "/favs" });
}); <!-- favorites.hbs --> <h2>Favorites<h2> <ul> {{#each}} <li> {{title}} </li> {{/each}} </ul> <!-- about.hbs --> <h1>About<h1> <h2>{{name}}<h2> <div class='bio'> {{bio}} </div> <!-- application.hbs --> <h1>Welcome to Ember.js</h1> <nav> {{#link-to 'about'}}About{{/link-to}} {{#link-to 'favorites'}}Favorites{{/link-to}} {{outlet}}<!-- filled with child template when you navigate into route --> </nav>
None
None
None
var Rdio = Ember.Application.create(); Rdio.Router.map(function(){}); Rdio.ApplicationRoute = Ember.Route.extend({ model: function(){
return $.ajax({ url: "/api/authenticate" }) } }); <!-- application.hbs --> {{outlet}} <!-- loading.hbs --> <div class="loading-container"> <span class="icon-loading spinner"/> </div>
None
{ username: 'trek', messageCount: 4, playlists: [ {id: 981, title:
"Everyday I'm shufflin'"}, {id: 191, title: "RUNNIN"} ] }
None
<div class='navigation'> <ul> <h3>Browse</h3> <li>{{#link-to "heavyRotation"}}Heavy Rotation{{/link-to}}</li> <li>{{#link-to "recentActivity"}}Recent Activity{{/link-to}}</li>
<li>{{#link-to "topCharts"}}Top Charts{{/link-to}}</li> <li>{{#link-to "newReleases"}}New Releases{{/link-to}}</li> <li>{{#link-to "stations"}}Stations{{/link-to}}</li> </ul>
<ul> <h3>Playlists</h3> <ul> {{#each playlists}} {{#link-to "playlist" this}} {{name}} {{/link-to}}
{{/each}} </ul> </ul>
<ul> <h3>Playlists</h3> <ul> {{#each playlists}} {{#link-to "playlist" this}} {{name}} {{/link-to}}
{{/each}} </ul> </ul> { username: 'trek', messageCount: 4, playlists: [ {id: 981, title: "Everyday I'm shufflin'"}, {id: 191, title: "RUNNIN"} ] }
<div class='top-bar'> <ul> <li>{{#link-to "profile"}}{{username}}{{/link-to}}</li> <li>{{#link-to "alets"}}{{messageCount}}{{/link-to}}</li> </ul>
<div class='top-bar'> <ul> <li>{{#link-to "profile"}}{{username}}{{/link-to}}</li> <li>{{#link-to "alets"}}{{messageCount}}{{/link-to}}</li> </ul> { username:
'trek', messageCount: 4, playlists: [ {id: 981, title: " {id: 191, title: " ] }
{{outlet}}
None
None
var Rdio = Ember.Application.create(); Rdio.Router.map(function(){}); Rdio.ApplicationRoute = Ember.Route.extend({ model: function(){
return $.ajax({ url: "/api/authenticate" }) } });
var Rdio = Ember.Application.create(); Rdio.Router.map(function(){ this.route("heavyRotation") }); Rdio.ApplicationRoute = Ember.Route.extend({
model: function(){ return $.ajax({ url: "/api/authenticate" }) } }); Rdio.HeavyRotationRoute = Ember.Route.extend({ model: function(){ return $.ajax({ url: "/api/heavyRotation" }) } });
None
[ { title: "The Speed of Things", artistName: "Dale Earnhardt
Jr. Jr.", songsCount: 13, isExplicit: false, imageUrl: "/images/c10efa31.png" }, { title: "I Love You", artistName: "The Neighbourhood", songsCount: 11, isExplicit: true, imageUrl: "/images/9ec1ce1.png" } {...}, {...} ]
None
<!-- heavyRotation.hbs --> <h3>Heavy Rotation</h3> {{#each}} {{link-to "album" this}} <div
class="album-"> </div> {{title}} {{artistName}} {{songsCount}} songs {{#if isExplicit}} EXPLICIT {{/if}} {{/link-to}} {{/each}}
<!-- heavyRotation.hbs --> <h3>Heavy Rotation</h3> {{#each}} {{link-to "album" this}} <div
class="album-"> </div> {{title}} {{artistName}} {{songsCount}} songs {{#if isExplicit}} EXPLICIT {{/if}} {{/link-to}} {{/each}} [ { title: "I Love You", artistName: "The Neighbourhood", songsCount: 11, isExplicit: true, imageUrl: "/images/9ec1ce1.png" } ]
None
None
None
Rdio.Router.map(function(){ this.route("heavyRotation"); this.route("album", {path: "album/:album_id"}); }); Rdio.AlbumRoute = Ember.Route.extend({ model:
function(params){ return $.ajax({ url: "/api/album/" + params.album_id }); } })
None
{ title: "The Speed of Things", artistName: "Dale Earnhardt Jr.
Jr.", songsCount: 13, isExplicit: false, imageUrl: "/images/c10efa31.png", playCount: 32694, songs: [ {trackNumber: 1, title: "Beautiful Dream"}, {trackNumber: 2, title: "Run"} ] }
None
None
None
None
None
Rdio.Router.map(function(){ this.resource("artist", {path: "artist/:artist_id"}, function(){ this.route("albums", {path: '/'}); this.route("songs"); })
}); Rdio.ArtistRoute = Ember.Route.extend({ model: function(params){ return $.ajax({ url: "/api/artist/" + params.artist_id }); } }); Rdio.ArtistAlbumsRoute = Ember.Route.extend({ model: function(parmas, transition){ return $.ajax({ url: "/api/artist/" + transition.params.artist_id + "/albums" }); } });
Rdio.Router.map(function(){ this.resource("artist", {path: "artist/:artist_id"}, function(){ this.route("albums", {path: '/'}); this.route("songs"); })
}); Rdio.ArtistRoute = Ember.Route.extend({ model: function(params){ return $.ajax({ url: "/api/artist/" + params.artist_id }); } }); Rdio.ArtistSongsRoute = Ember.Route.extend({ model: function(parmas, transition){ return $.ajax({ url: "/api/artist/" + transition.params.artist_id + "/songs" }); } });
None
None
None
None
None
None
None
None
None
None
None
<!-- application.hbs --> {{outlet}} {{outlet "playbar"}}
<!-- application.hbs --> {{outlet}} {{outlet "playbar"}}
Rdio.ApplicationRoute = Ember.Route.extend({ model: function(){ return $.ajax({ url: "/api/authenticate" })
} });
Rdio.ApplicationRoute = Ember.Route.extend({ model: function(){ return $.ajax({ url: "/api/authenticate" })
}, renderTemplate: function(){ this._super(); this.render('playbar', { into: 'application', outlet: 'playbar' }); } });
None
None
{{#each tracks}} <ul> <li> {{trackNumber}} {{name}} </li> </ul> {{/each}}
{{#each tracks}} <ul> <li {{action "play" this}}> {{trackNumber}} {{name}} </li>
</ul> {{/each}}
current controller current route {{#each tracks}} <ul> <li {{action "play"
this}}> {{trackNumber}} {{name}} </li> </ul> {{/each}} parent route application route ...
Rdio.ApplicationRoute = Ember.Route.extend({ actions: { play: function(song){ this.controllerFor('playbar').send('play', song); }
} });
Rdio.ApplicationRoute = Ember.Route.extend({ actions: { play: function(song){ this.controllerFor('playbar').send('play', song); }
} }); Rdio.PlaybarController = Ember.Controller.extend({ actions: { play: function(song){ ... } } });
None