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
Building Evented Single Page Applications
Search
John Nunemaker
PRO
September 13, 2009
Programming
93
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Building Evented Single Page Applications
Given at jQuery conf in Boston.
John Nunemaker
PRO
September 13, 2009
More Decks by John Nunemaker
See All by John Nunemaker
Remote First: Building Distributed Teams that Win
jnunemaker
PRO
1
170
AI: The stuff that nobody shows you
jnunemaker
PRO
8
760
Atom
jnunemaker
PRO
10
5.2k
MongoDB for Analytics
jnunemaker
PRO
11
1.1k
Addicted to Stable
jnunemaker
PRO
32
2.9k
MongoDB for Analytics
jnunemaker
PRO
21
2.3k
MongoDB for Analytics
jnunemaker
PRO
16
30k
Why You Should Never Use an ORM
jnunemaker
PRO
61
9.9k
Why NoSQL?
jnunemaker
PRO
10
1k
Other Decks in Programming
See All in Programming
エンジニア向け会社紹介/Findy Company Profile
findyinc
6
360k
決定論的オーケストレーションの設計と実装 / Design and Implementation of Deterministic Orchestration
nrslib
4
1.6k
Strategic Design in the Frontend: Moduliths & Micro Frontends @DDDEurope
manfredsteyer
PRO
0
140
Language Server 使ってる? 〜VSCode と Zed の場合〜 / Are you using a Language Server? ~For VS Code and Zed~
handlename
0
820
Observability in Practice:Grafana 與 Edge Device SRE 的那些事
blueswen
0
190
Webフレームワークの ベンチマークについて
yusukebe
0
190
メソッドのジェネリクスでGoの夢は広がるか? / Kyoto.go #65
utgwkk
3
1k
SLOをサービス品質の共通言語にするために 取り組んできたこと
wakana0222
0
290
【やさしく解説 設計編 #0】DDDのコード、読めるのに分からない人へ
panda728
PRO
1
180
Generative UI & AI-Assistants for Your Angular Solutions
manfredsteyer
PRO
0
110
SREは、MCPとSRE Agentをこう使え!
kazumax55
0
130
そのテスト、説明できますか?~LWテスト戦略FW~のご紹介
nakahara
0
190
Featured
See All Featured
Measuring & Analyzing Core Web Vitals
bluesmoon
9
880
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
9
1.4k
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
31
10k
Odyssey Design
rkendrick25
PRO
2
720
Typedesign – Prime Four
hannesfritz
42
3.1k
Mind Mapping
helmedeiros
PRO
1
280
Joys of Absence: A Defence of Solitary Play
codingconduct
1
410
Intergalactic Javascript Robots from Outer Space
tanoku
273
27k
Building the Perfect Custom Keyboard
takai
2
810
SEO Brein meetup: CTRL+C is not how to scale international SEO
lindahogenes
1
2.8k
SEO in 2025: How to Prepare for the Future of Search
ipullrank
3
3.6k
The AI Search Optimization Roadmap by Aleyda Solis
aleyda
1
6k
Transcript
building evented single-page applications Sunday, September 13, 2009
1. who 2. why 3. demo 4. how Sunday, September
13, 2009
1. who Sunday, September 13, 2009
chancellor http://orderedlist.com/ Sunday, September 13, 2009
professor http://teaching.johnnunemaker.com/ Sunday, September 13, 2009
rubyist http://railstips.org/ Sunday, September 13, 2009
i’m not perfect Sunday, September 13, 2009
2. why Sunday, September 13, 2009
because? Sunday, September 13, 2009
because? Sunday, September 13, 2009
speed only send what changes across the wire Sunday, September
13, 2009
perceived speed Sunday, September 13, 2009
interactivity Sunday, September 13, 2009
experience but the greatest of these is... Sunday, September 13,
2009
3. demo Sunday, September 13, 2009
http://peoplebase.com/ http://harmonyapp.com/ Sunday, September 13, 2009
4. how Sunday, September 13, 2009
goals Sunday, September 13, 2009
no reloads Sunday, September 13, 2009
no reloads history/refresh Sunday, September 13, 2009
no reloads history/refresh easy Sunday, September 13, 2009
# Sunday, September 13, 2009
no reloads history/refresh easy Sunday, September 13, 2009
no reloads history/refresh easy Sunday, September 13, 2009
no reloads history/refresh easy Sunday, September 13, 2009
no reloads history/refresh easy Sunday, September 13, 2009
the end Sunday, September 13, 2009
no reloads Sunday, September 13, 2009
<a href="#/items">Items</a> Sunday, September 13, 2009
$("a[href^='#/']").live('click', function (event) { var $link = $(this); window.location.hash =
$link.attr('href'); $(document).trigger('hashchange'); return false; }); Sunday, September 13, 2009
$(document).bind('hashchange', Layout.reload); Sunday, September 13, 2009
var Layout = { reload: function() { Layout.load(window.location.hash); } };
Sunday, September 13, 2009
var Layout = { load: function(path, options) { path =
path.replace(/^#/, ''); // trigger path loading events $.ajax({ url : path, dataType : 'json', success : function(json) { Layout.onSuccess(json); // trigger path success events if (options && options.success) { options.success(); } }, complete : function() { if (options && options.complete) { options.complete(); } } }); } }; Sunday, September 13, 2009
var Layout = { load: function(path, options) { path =
path.replace(/^#/, ''); $(document).trigger('path:loading', [path]); $(document).trigger('path:loading:' + path); $.ajax({ url: path, dataType: 'json', success: function(json) { Layout.onSuccess(json); $(document).trigger('path:success', [path, json]); $(document).trigger('path:success:' + path, [json]); if (options && options.success) { options.success(); } }, complete: function() { if (options && options.complete) { options.complete(); } } }); } }; Sunday, September 13, 2009
var Layout = { onSuccess: function(json) { Layout.applyJSON(json); // trigger
layout success }, }; Sunday, September 13, 2009
no reloads Sunday, September 13, 2009
history/refresh Sunday, September 13, 2009
setInterval(function() { var hash_is_new = window.location.hash && window.currentHash != window.location.hash;
if (hash_is_new) { window.currentHash = window.location.hash; Layout.handlePageLoad(); } }, 300); Sunday, September 13, 2009
#/org/groups/12/45/new Sunday, September 13, 2009
org groups 12 45 new Sunday, September 13, 2009
org groups 12 45 new Sunday, September 13, 2009
org groups 12 45 new Sunday, September 13, 2009
org groups 12 45 new Sunday, September 13, 2009
org groups 12 45 new Sunday, September 13, 2009
org groups 12 45 new Sunday, September 13, 2009
var Layout = { handlePageLoad: function() { var segments =
window.location.hash.replace(/^#\//, '').split('/'), total = segments.length, path = ''; function loadSectionsInOrder() { var segment = segments.shift(); path += '/' + segment; var onComplete = function() { var loaded = total - segments.length, finished = loaded == total; if (!finished) { loadSectionsInOrder(); } }; Layout.load(path, {complete: onComplete}); } loadSectionsInOrder(); } }; Sunday, September 13, 2009
var Layout = { handlePageLoad: function() { var segments =
window.location.hash.replace(/^#\//, '').split('/'), total = segments.length, path = ''; $(document).trigger('page:loading'); function loadSectionsInOrder() { var segment = segments.shift(); path += '/' + segment; var onComplete = function() { var loaded = total - segments.length, finished = loaded == total; $(document).trigger('page:progress', [total, loaded]); if (finished) { $(document).trigger('page:loaded'); } else { loadSectionsInOrder(); } }; Layout.load(path, {complete: onComplete}); } loadSectionsInOrder(); } }; Sunday, September 13, 2009
$(document).bind('page:progress', function(e, total, loaded) { if (total != loaded) {
var final_width = 114, new_width = (loaded/total) * final_width; $('#loading_progress').animate({width: new_width+'px'}, 200); } }); $(document).bind('page:loading', function() { $('#harmony_loading').show(); $('#loading_progress').css('width', 0); }); $(document).bind('page:loaded', function() { $('#loading_progress').animate({width:'114px'}, 300, 'linear', function() { $('#harmony_loading').hide(); }); }); Sunday, September 13, 2009
history/refresh Sunday, September 13, 2009
easy Sunday, September 13, 2009
rule #1: abuse events for better code separation and easier
customization http://orderedlist.com/articles/jquery-evented-programming-primer Sunday, September 13, 2009
$('form').live('submit', function(event) { var $form = $(this); $form.ajaxSubmit({ dataType: 'json',
beforeSend: function() { // trigger before send }, success: function(json) { // if errors, show them, else apply json and reset form }, error: function(response, status, error) { // trigger error }, complete: function() { // trigger complete } }); return false; }); Sunday, September 13, 2009
$('form').live('submit', function(event) { var $form = $(this); $form.ajaxSubmit({ dataType: 'json',
beforeSend: function() { $form.trigger('form:beforeSend'); }, success: function(json) { if (json.errors) { $form.showErrors(json.errors); } else { Layout.onSuccess(json); $form.trigger('form:success', [json]); $form.resetForm(); } }, error: function(response, status, error) { $form.trigger('form:error', [response, status, error]); }, complete: function() { $form.trigger('form:complete'); } }); return false; }); Sunday, September 13, 2009
var Site = { onCreateSuccess: function(event, json) { Sidebar.highlight($('#site_' +
json.id)) Layout.updateHashWithoutLoad(window.location.hash.replace(/new$/, json.id)); }, onUpdateSuccess: function(event, json) { Sidebar.highlight($('#site_' + json.id)) } }; $('form.new_site').live('form:success', Site.onCreateSuccess); $('form.edit_site').live('form:success', Site.onUpdateSuccess); Sunday, September 13, 2009
var Field = { onCreateSuccess: function(event, json) { $('#list_section_' +
json.section_id) .addSectionField(json.field_title.toLowerCase()); }, onUpdateSuccess: function(event, json) { $('#list_section_' + json.section_id) .removeSectionField(json.old_title.toLowerCase()) .addSectionField(json.new_title.toLowerCase()); } }; $('form.new_field') .live('form:success', Field.onCreateSuccess); $('form.edit_field').live('form:success', Field.onUpdateSuccess); Sunday, September 13, 2009
Layout.applyJSON accepts json like below and “applies” it to the
layout; gets called with each url load either from click or form Sunday, September 13, 2009
Layout.applyJSON { 'replace': { '#content': '<h1>Heading</h1><p>Yay!</p>' }, 'replaceWith': { '#post_12':
'<div class="post">...</div>' }, 'remove': ['#post_11', '#comment_12'] } Sunday, September 13, 2009
rule #2: the url dictates everything Sunday, September 13, 2009
var Layout = { livePath: function(event, path, callback) { if
(typeof(test) === 'string') { $(document).bind('path:' + event + ':' + path, callback); } else { Layout.live_path_regex[event].push([path, callback]); } } }; Sunday, September 13, 2009
Layout.livePath('loading', /\/org\/([^\/]+)([0-9\/]+).*/, Groups.loading); Layout.livePath('loading', /\/sections\/([0-9]+)$/, Sections.markCurrent); Layout.livePath('success', '/org/groups', Groups.setup); Layout.livePath('success',
'/sections', Sections.makeSortable); Layout.livePath('success', /\/admin\/assets(.*)/, Assets.init); Layout.livePath('success', /\/admin\/items\/(\d+)/, ItemForm.init); Layout.livePath('success', /\/admin\/items\/([0-9\/]+)/, Items.manageSidebar); Sunday, September 13, 2009
rule #3: do it live Sunday, September 13, 2009
$('a.field_form_toggler') .live('click', Fields.toggleAddFieldForm); $('form.new_section') .live('form:success', SectionForm.onCreateSuccess); $('form.edit_section') .live('form:success', SectionForm.onUpdateSuccess); $('form.new_field')
.live('form:success', Field.onCreateSuccess); $('form.edit_field') .live('form:success', Field.onUpdateSuccess); $('a.field_destroy') .live('destroy:success', Field.onDestroySuccess); Sunday, September 13, 2009
easy Sunday, September 13, 2009