Using Templates to Achieve Awesomer Architecture
-
Upload
garann-means -
Category
Technology
-
view
31 -
download
0
description
Transcript of Using Templates to Achieve Awesomer Architecture
using templates to achieve
AWESOMER architecture
Sunday, October 17, 2010
hi!Garann “it’s like Karen with a G” Means
HTML, CSS, JS at Gerson Lehrman Group
Austin, TX
garann.com / [email protected] / @garannm
Sunday, October 17, 2010
ask me how i reduced 12k lines of js to 4k
Sunday, October 17, 2010
get that nowhttp://github.com/jquery/jquery-tmpl
Sunday, October 17, 2010
alternatives?
Sunday, October 17, 2010
var container = $(“div.band-info”);container.append(“h2”);container.find(“h2”).html(band.bandName);$.each(band.members,function() {var span = container.append(“span”).addClass(“band-member”);
span.html(this.name+“ - “+this.instrument);});if (band.single) {var link = container.append(“a”).attr(“href”,band.single.url);
link.text(‘Download “‘+band.single.title+‘“‘);
}
dom manipulation
Sunday, October 17, 2010
var container = $(“div.band-info”);container.find(“h2”).html(band.bandName);var link = container.find(“a”);$.each(band.members,function() {link.before(‘<span class=”band-member”>’ + this.name + ‘ - ‘ + this.instrument + ‘</span>’);
});if (band.single) {link.attr(“href”,band.single.url);link.text(band.single.title);
} else { link.hide();
}
hidden element “templates”
ps: still dom manipulationSunday, October 17, 2010
var html = new Array();html.push(‘<div class=”band-info”><h2>’);html.push(band.bandName + ‘</h2>’);$.each(band.members,function() {html.push(‘<span class=”band-member”>’);html.push(this.name + ‘ - ‘);html.push(this.instrument + ‘</span>’);
});if (band.single) {html.push(‘<a href=”’ + band.single.url);html.push(‘”>Download “‘);html.push(band.single.title + ‘”</a>’);
}html.push(‘</div>’);document.append(html.join(“”));
concatenation
Sunday, October 17, 2010
what about just returning html from an xhr?
send the same data over and over
have to dig properties out of DOM
building HTML server-side is annoying
Sunday, October 17, 2010
that’s not an architecture#thatsaproblem
Sunday, October 17, 2010
an AWESOMER architecture:separates the presentation from the data
abstracts views into reusable components
markup changes in one place
flexibility to treat big and small views differently
where you need it when you need it
Sunday, October 17, 2010
pros and cons
no templates templatesSunday, October 17, 2010
performanceSunday, October 17, 2010
DRYSunday, October 17, 2010
minimize dom manipulationSunday, October 17, 2010
maintainabilitySunday, October 17, 2010
lazy loadingSunday, October 17, 2010
<script type=”text/html”><div class=”band-info”><h2>${bandName}</h2>{{each members}}<span class=”band-member”>${$value.name} - ${$value.instrument}
</span>{{/each}}{{if single}}<a href=”${single.url}”>Download “${single.title}”</a>
{{/if}}</div>
</script>
what a template looks like
Sunday, October 17, 2010
<script type=”text/html”><div class=”band-info”><h2>${bandName}</h2>{{each members}}<span class=”band-member”>${$value.name} - ${$value.instrument}
</span>{{/each}}{{if single}}<a href=”${single.url}”>Download “${single.title}”</a>
{{/if}}</div>
</script>
what a template looks like
Sunday, October 17, 2010
exciting syntax!
Sunday, October 17, 2010
${bandName} is the world’s greatest band.
Everyone loves {{= bandName}}.
properties
Sunday, October 17, 2010
${bandName} has ${fans.length} fans
${bandName} has ${fans.length} fan${fans.length == 1 ? ‘’ : ‘s’}
${bandName} has ${fans.length} ${myApp.pluralize(‘fan’)}
expressions
Sunday, October 17, 2010
{{if fans.length}}
${bandName} has ${fans.length}${myApp.pluralize(‘fan’)}
{{else}}
You’ve probably never heard of ${bandName}. They’re really obscure.
{{/if}}
if / else
Sunday, October 17, 2010
{{each members}}
${$value.name} plays the ${$value.instrument} like a GOD.
You heard me. ${this.name} practically invented the ${this.instrument}.
{{/each}}
each
Sunday, October 17, 2010
<script type=”text/html” id=”footer-tmpl”>Comments:{{tmpl(comments) “#comment-tmpl”}}
</script>
<script type=”text/html” id=”comment-tmpl”><div class="comment"><span class="commentor">${commentor} said:</span>
<p>${text}</p><span class="timestamp">on ${timestamp.toLocaleDateString()}</span>
</div></script>
nested template
Sunday, October 17, 2010
<script type=”text/html” id=”footer-tmpl”>Comments:{{tmpl(comments) “commentTempl”}}
</script>
<script type=”text/html” id=”comment-tmpl”><div class=”comment”><span>${commentor} said:</span><p>${text}</p><span>on ${timestamp.toDateString()}</span>
</div></script>
<script type=”text/javascript”>$(“#comment-tmpl”).template(“commentTempl”);
</script>
compiled template
Sunday, October 17, 2010
other tags{{! this is a comment}}
{{html thingThatShouldntBeEscaped}}
{{wrap "#otherTmpl”}}<div class=”thing”>One</div><div class=”otherThing”>Two</div>
{{/wrap}}
Sunday, October 17, 2010
thismain template: refer to properties directly
$item, $item.data, $data
{{each}}: $value
nested template: parent’s data or whatever you passed in
Sunday, October 17, 2010
how do they work?
Sunday, October 17, 2010
$.tmpl(“comments”,data.comments).appendTo(“#container”);
$(“#comment-tmpl”).tmpl(data.comments).appendTo(“#container”);
$(document).html($(“#justsayin”).tmpl(data));
rendering
Sunday, October 17, 2010
$.tmplString immediately parsed and evaluated
Tags translated to expressions
Return a jQuery object
Sunday, October 17, 2010
$.template(“veryShortTmpl”,”<b>${name}</b>”);
$(“#stuff-tmpl”).template(“wickedCoolTmpl”);
compiling
Sunday, October 17, 2010
$.templateParse the template but don’t populate
Template engine saves in a big ol’ list
Rendering with data like calling a function
Sunday, October 17, 2010
var t = $(“div.comment:last”).tmplItem();
var lastId = t.data.id;
t.tmpl = $.template(“new-tmpl”);t.update();
get and set
Sunday, October 17, 2010
$.tmplItemtmplItem has additional functions and properties
nodes, parent, html, nest, wrap
Functions remain available to object in DOM
Sunday, October 17, 2010
event handling
Sunday, October 17, 2010
$(“#some-tmpl”).tmpl(data).appendTo(“#thing”);
$(“a.childOfThing”).click(function(e) {e.preventDefault();doMoreStuff();
});
weak
Sunday, October 17, 2010
// in some function$(“#some-tmpl”).tmpl(data).appendTo(“#thing”);
// wherever$(“a.childOfThing”).live(“click”,function(e) {e.preventDefault();doMoreStuff();
});
awesomeuse live() for events on multiple pages
or for things that change containers
Sunday, October 17, 2010
// in some function$(“#some-tmpl”).tmpl(data).appendTo(“#thing”);
// wherever$(“#thing”).delegate(“a.childOfThing”,“click”,function(e) {e.preventDefault();doMoreStuff();
});
AWESOMER!use delegate() for events on one page
or always in the same container
Sunday, October 17, 2010
when the only tool you have is a hammer..
oh wait you have CSS
Sunday, October 17, 2010
$(“#some-tmpl”).tmpl(data).appendTo(“#thing”);
$(“#childOfThing”).tmplItem().tmpl =$(“#state-two-tmpl”).template();
awesome
Sunday, October 17, 2010
$(“#some-tmpl”).tmpl(data).appendTo(“#thing”);
$(“#childOfThing”).removeClass(“stateOne”).addClass(“stateTwo”);
AWESOMER!use CSS where possible - it’s faster!
Sunday, October 17, 2010
css is better for..errors
small number of elements being shown/hidden
elements with plugins attached
input areas that may have unsubmitted user data
Sunday, October 17, 2010
fast, good, cheap:pick two and a half
Sunday, October 17, 2010
faster-ish templatesbreak up the family
separate pattern templates from interface templates
Always Be Compiling
templates = functions
Sunday, October 17, 2010
stop sending html
Sunday, October 17, 2010
myApp.container = $(“#stuffContainer”);
$(“a.showMore”).click(function() {
$.get(“/moreStuff”,function(items) {
$(“#item-tmpl”).tmpl(items).appendTo(myApp.container);
});
});
pagination
Sunday, October 17, 2010
window.setTimeout(checkForStuff, 30000);
function checkForStuff() {$.get(“/moreStuff”,function(items) {if (items.length) {var d = {l: items.length, d: items };$(“#load-new-btn-tmpl”).tmpl(d).prependTo(myApp.container);
}window.setTimeout(checkForStuff, 30000);
});}$(“#loadNewBtn”).live(“click”,function(e) {$(this).tmplItem().tmpl = $.template(“new-tmpl”);
});
polling for new data
Sunday, October 17, 2010
$(“#anEditButton”).live(“click”,function() {$(“#thisGuysParent”).tmplItem().tmpl = $(“#edit-mode-tmpl”).template();
});
inline edit
Sunday, October 17, 2010
yo dawg we heard you like plugins
Sunday, October 17, 2010
$.fn.myPlugin = function(options) {this.html(‘<div class=”’ + options.class + ’”>’ + options.content + ‘<a href=”#”>’ +options.buttonLabel + ‘</a></div>’);
...return this;
}
weak
Sunday, October 17, 2010
$.fn.myPlugin = function(options) {this.html($.tmpl(“myTemplate”,options));...return this;
}
AWESOMER!
Sunday, October 17, 2010
$.fn.myPlugin.update = function(newOpts) {this.html(‘<div class=”’ + newOpts.class + ’”>’ + newOpts.content + ‘<a href=”#”>’ +newOpts.buttonLabel + ‘</a></div>’);...
}
weak
Sunday, October 17, 2010
$.fn.myPlugin.update = function(newOpts) {this.tmplItem().data = newOpts;...
}
AWESOMER!
Sunday, October 17, 2010
AWESOMER pluginsNo more DOM manipulation
Don’t have to require a template engine *
Sexy updates and redraws
Sunday, October 17, 2010
where do templates come from?
Sunday, October 17, 2010
var myTemplate = ‘<div class="band-info"><img src="/images/${photo}" alt="${bandName}" /><h2>${bandName}</h2>{{each members}}! ! ! ! <span class="band-member">! ! ! ! ! ${this.name} - ${this.instrument}! ! ! ! </span>! ! ! {{/each}}</div>’;
$.tmpl(myTemplate,data).appendTo(container);
in your javascript
eeeeek.Sunday, October 17, 2010
<script type=”text/html” id=”my-tmpl”><div class="band-info"><img src="/images/${photo}" alt="${bandName}" />
<h2>${bandName}</h2>{{each members}}
! ! ! ! <span class="band-member">! ! ! ! ! ${this.name} - ${this.instrument}! ! ! ! </span>! ! ! {{/each}}</div>
</script>
$(“#my-tmpl”).tmpl(data).appendTo(container);
in your html
Sunday, October 17, 2010
if ($.template("commentTmpl").length) {updateComment(comment);
} else {$.get("comment-tmpl.js", function(response) {
$.template("commentTmpl",response);updateComment(comment);
});}
function updateComment(comment) {// rendering happens here
}
external files
hint: ftwSunday, October 17, 2010
use external files if you enjoy:
Having your templates cached
Only loading code once it’s needed
Better code organization
Using your client-side templates for server-side rendering
Sunday, October 17, 2010
little external templatesput lots of little strings in one file
like a constants file
e.g. internationalization
small patterns available everywhere
Sunday, October 17, 2010
what about clients without js?
Sunday, October 17, 2010
noscriptssrsly?
clientside templates on the serverside
Sunday, October 17, 2010
two-fer-one
Sunday, October 17, 2010
#newtwitter’s doing itSunday, October 17, 2010
node.js is doing itSunday, October 17, 2010
takes a little doinghave to write a backend parser
may limit native functions like length()
unless your backend is JS
custom functions pretty much out
unless your backend is JS
even truthy and falsey may be a problem
now you’re just showing off.
DEMO NAO PLZ
Sunday, October 17, 2010
does this template engine come in green?
Sunday, October 17, 2010
micro-templatesSunday, October 17, 2010
mustacheSunday, October 17, 2010
jTemplatesSunday, October 17, 2010
pureSunday, October 17, 2010
check out:jQuery templates: github.com/jquery/jquery-tmpl/
documentation: http://api.jquery.com/(scroll to the very bottom)
jQuery templates for node.js:github.com/kof/node-jqtpl
jQuery templates for .NET:github.com/awhatley/jquery-tmpl.net
photo credit: http://www.flickr.com/photos/ennuiislife/
Sunday, October 17, 2010
i appreciate ya!
keep in touch: @garannm / [email protected] code: github.com/garann/templates-example
Sunday, October 17, 2010