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
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
John Nunemaker
PRO
September 13, 2009
Programming
100
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
190
AI: The stuff that nobody shows you
jnunemaker
PRO
9
970
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
10k
Why NoSQL?
jnunemaker
PRO
10
1k
Other Decks in Programming
See All in Programming
Oxlintはいいぞ(続)
yug1224
1
540
レビュー履歴をAIに食わせて、 Compose移行を加速するs
shihochan
0
260
まずはプロンプトガイドを読もう、話はそれからだ
kiakiraki
1
260
Vibes Containers 〜AIで変わるコンテナ設計と運用〜
tkikuc
1
480
Go を使い始めて 2 ヶ月の学び / My first two months with Go
contour_gara
0
420
一参加者から『中の人』へ 〜全通PHPerがブースに立って学んだ、カンファレンスを100倍楽しむコツ〜
wp_daisuke
0
110
AWS Step Functions 大規模並列の壁を越える / jaws-sonic-2026-niigata-step-functions
kasacchiful
PRO
0
360
新人はどこまで自力でやり、どこからAIに頼るべきか/エンジニア育成に向き合う_先輩たちの悩みと知見共有会
toppan_digital_dev
1
560
PyConJP2026_wat_Python × Signal Processing: How to Draw Pictures with Sound Using Spectrogram Art
wat
0
670
AIと壁打ちしながら進めるコスト管理
fufuhu
2
1.9k
AIを上手に使っていこうとしたら越境せざるを得なくなった話 〜実践1年で見えた境界を越えなければならない理由と進め方〜 / Crossing borders with AI
tomoyakitaura
3
1k
FDEとは、何者なのか?
masapyon1212
0
140
Featured
See All Featured
Thoughts on Productivity
jonyablonski
76
5.4k
Applied NLP in the Age of Generative AI
inesmontani
PRO
4
2.4k
How to Create Impact in a Changing Tech Landscape [PerfNow 2023]
tammyeverts
56
3.5k
Building a Scalable Design System with Sketch
lauravandoore
463
34k
Unsuck your backbone
ammeep
672
58k
GraphQLとの向き合い方2022年版
quramy
50
15k
Rails Girls Zürich Keynote
gr2m
96
14k
A Guide to Academic Writing Using Generative AI - A Workshop
ks91
PRO
1
420
Pawsitive SEO: Lessons from My Dog (and Many Mistakes) on Thriving as a Consultant in the Age of AI
davidcarrasco
0
240
How to Align SEO within the Product Triangle To Get Buy-In & Support - #RIMC
aleyda
2
1.8k
Why Our Code Smells
bkeepers
PRO
340
58k
Lightning talk: Run Django tests with GitHub Actions
sabderemane
0
250
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