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
430
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
210
Beyond Front-end Developer
trek
1
470
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
2k
Cargo Cults
trek
0
320
Other Decks in Technology
See All in Technology
ソフトウェア エンジニアとしての 姿勢と心構え
recruitengineers
PRO
22
12k
現場が抱える様々な問題は “組織設計上” の問題によって生じていることがある / Team-oriented Organization Design 20250827
mtx2s
7
66k
ヘブンバーンズレッドのレンダリングパイプライン刷新
gree_tech
PRO
0
330
役割は変わっても、変わらないもの 〜スクラムマスターからEMへの転身で学んだ信頼構築の本質〜 / How to build trust
shinop
0
140
絶対に失敗できないキャンペーンページの高速かつ安全な開発、WINTICKET × microCMS の開発事例
microcms
0
300
AI時代に非連続な成長を実現するエンジニアリング戦略
sansantech
PRO
3
820
ヒューリスティック評価を用いたゲームQA実践事例
gree_tech
PRO
0
320
VPC Latticeのサービスエンドポイント機能を使用した複数VPCアクセス
duelist2020jp
0
340
Vault meets Kubernetes
mochizuki875
0
140
ZOZOマッチのアーキテクチャと技術構成
zozotech
PRO
1
110
異業種出身エンジニアが気づいた、転向して十数年経っても変わらない自分の武器とは
macnekoayu
0
230
AIエージェント就活入門 - MCPが履歴書になる未来
eltociear
0
670
Featured
See All Featured
Chrome DevTools: State of the Union 2024 - Debugging React & Beyond
addyosmani
7
830
Imperfection Machines: The Place of Print at Facebook
scottboms
268
13k
RailsConf 2023
tenderlove
30
1.2k
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
8
900
The Invisible Side of Design
smashingmag
301
51k
ピンチをチャンスに:未来をつくるプロダクトロードマップ #pmconf2020
aki_iinuma
126
53k
Six Lessons from altMBA
skipperchong
28
4k
GraphQLの誤解/rethinking-graphql
sonatard
71
11k
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
30
9.6k
The Language of Interfaces
destraynor
160
25k
StorybookのUI Testing Handbookを読んだ
zakiyama
30
6k
Unsuck your backbone
ammeep
671
58k
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