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
460
2
Share
The Rendering Revolution: Running Apps in the Browser with Ember.js
Trek Glowacki
October 24, 2013
More Decks by Trek Glowacki
See All by Trek Glowacki
Documents are not the web
trek
1
250
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
340
Other Decks in Technology
See All in Technology
研究開発部メンバーの働き⽅ / Sansan R&D Profile
sansan33
PRO
4
23k
Autonomous Database - Dedicated 技術詳細 / adb-d_technical_detail_jp
oracle4engineer
PRO
5
13k
ふりかえりがなかった職能横断チームにふりかえりを導入してみて学んだこと 〜チームのふりかえりを「みんなで未来を考える場」にするプロローグ設計〜
masahiro1214shimokawa
0
340
試されDATA SAPPORO [LT]Claude Codeで「ゆっくりデータ分析」
ishikawa_satoru
0
360
DIPS2.0データに基づく森林管理における無人航空機の利用状況
naokimuroki
0
190
ルールルルルル私的函館観光ガイド── 函館の街はイクラでも楽しめる!
nomuson
0
120
ストライクウィッチーズ2期6話のエイラの行動が許せないのでPjMの観点から何をすべきだったのかを考える
ichimichi
1
320
本番環境でPHPコードに触れずに「使われていないコード」を調べるにはどうしたらよいか?
egmc
1
270
New CBs New Challenges
ysuzuki
1
170
Databricksを用いたセキュアなデータ基盤構築とAIプロダクトへの応用.pdf
pkshadeck
PRO
0
290
Discordでリモートポケカしてたら、なぜかDOを25分間動かせるようになった話
umireon
0
120
LLM とプロンプトエンジニアリング/チューターを定義する / LLMs and Prompt Engineering, and Defining Tutors
ks91
PRO
0
330
Featured
See All Featured
Navigating Team Friction
lara
192
16k
Building Better People: How to give real-time feedback that sticks.
wjessup
370
20k
Building the Perfect Custom Keyboard
takai
2
720
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
37
6.3k
Side Projects
sachag
455
43k
Build your cross-platform service in a week with App Engine
jlugia
234
18k
Groundhog Day: Seeking Process in Gaming for Health
codingconduct
0
140
The Invisible Side of Design
smashingmag
302
51k
Efficient Content Optimization with Google Search Console & Apps Script
katarinadahlin
PRO
1
480
A Soul's Torment
seathinner
6
2.6k
Connecting the Dots Between Site Speed, User Experience & Your Business [WebExpo 2025]
tammyeverts
11
880
Building Experiences: Design Systems, User Experience, and Full Site Editing
marktimemedia
0
480
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