Using Templates to Achieve Awesomer Architecture

33,593 views
33,297 views

Published on

Templates are the best kind of tool: simple to write and implement, but powerful enough to make your architecture slicker and your code leaner. Getting markup out of your Javascript is a huge deal, but templates can help with more than that. They can manage repeated code snippets, allow you to deftly switch states in single page applications, and help keep your code DRY when supporting users with and without Javascript enabled. Using and extending them creatively can make any architecture a little awesomer.

Published in: Technology
6 Comments
62 Likes
Statistics
Notes
No Downloads
Views
Total views
33,593
On SlideShare
0
From Embeds
0
Number of Embeds
947
Actions
Shares
0
Downloads
446
Comments
6
Likes
62
Embeds 0
No embeds

No notes for slide

Using Templates to Achieve Awesomer Architecture

  1. 1. using templates to achieve AWESOMER architecture Sunday, October 17, 2010
  2. 2. hi! Garann “it’s like Karen with a G” Means HTML, CSS, JS at Gerson Lehrman Group Austin, TX garann.com / garann@gmail.com / @garannm Sunday, October 17, 2010
  3. 3. ask me how i reduced 12k lines of js to 4k Sunday, October 17, 2010
  4. 4. get that now http://github.com/jquery/jquery-tmpl Sunday, October 17, 2010
  5. 5. alternatives? Sunday, October 17, 2010
  6. 6. dom manipulation 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+‘“‘); } Sunday, October 17, 2010
  7. 7. hidden element “templates” 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(); } ps: still dom manipulation Sunday, October 17, 2010
  8. 8. concatenation 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(“”)); Sunday, October 17, 2010
  9. 9. 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
  10. 10. that’s not an architecture #thatsaproblem Sunday, October 17, 2010
  11. 11. 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
  12. 12. pros and cons no templates templates Sunday, October 17, 2010
  13. 13. performance Sunday, October 17, 2010
  14. 14. DRY Sunday, October 17, 2010
  15. 15. minimize dom manipulation Sunday, October 17, 2010
  16. 16. maintainability Sunday, October 17, 2010
  17. 17. lazy loading Sunday, October 17, 2010
  18. 18. what a template looks like <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> Sunday, October 17, 2010
  19. 19. what a template looks like <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> Sunday, October 17, 2010
  20. 20. exciting syntax! Sunday, October 17, 2010
  21. 21. properties ${bandName} is the world’s greatest band. Everyone loves {{= bandName}}. Sunday, October 17, 2010
  22. 22. expressions ${bandName} has ${fans.length} fans ${bandName} has ${fans.length} fan${fans.length == 1 ? ‘’ : ‘s’} ${bandName} has ${fans.length} ${myApp.pluralize(‘fan’)} Sunday, October 17, 2010
  23. 23. if / else {{if fans.length}} ${bandName} has ${fans.length} ${myApp.pluralize(‘fan’)} {{else}} You’ve probably never heard of ${bandName}. They’re really obscure. {{/if}} Sunday, October 17, 2010
  24. 24. each {{each members}} ${$value.name} plays the ${$value.instrument} like a GOD. You heard me. ${this.name} practically invented the ${this.instrument}. {{/each}} Sunday, October 17, 2010
  25. 25. nested template <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> Sunday, October 17, 2010
  26. 26. compiled template <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> Sunday, October 17, 2010
  27. 27. 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
  28. 28. this main 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
  29. 29. how do they work? Sunday, October 17, 2010
  30. 30. rendering $.tmpl(“comments”,data.comments).appendTo (“#container”); $(“#comment-tmpl”).tmpl (data.comments).appendTo(“#container”); $(document).html($(“#justsayin”).tmpl(data)); Sunday, October 17, 2010
  31. 31. $.tmpl String immediately parsed and evaluated Tags translated to expressions Return a jQuery object Sunday, October 17, 2010
  32. 32. compiling $.template(“veryShortTmpl”,”<b>${name}</b>”); $(“#stuff-tmpl”).template(“wickedCoolTmpl”); Sunday, October 17, 2010
  33. 33. $.template Parse 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
  34. 34. get and set var t = $(“div.comment:last”).tmplItem(); var lastId = t.data.id; t.tmpl = $.template(“new-tmpl”); t.update(); Sunday, October 17, 2010
  35. 35. $.tmplItem tmplItem has additional functions and properties nodes, parent, html, nest, wrap Functions remain available to object in DOM Sunday, October 17, 2010
  36. 36. event handling Sunday, October 17, 2010
  37. 37. weak $(“#some-tmpl”).tmpl(data).appendTo(“#thing”); $(“a.childOfThing”).click(function(e) { e.preventDefault(); doMoreStuff(); }); Sunday, October 17, 2010
  38. 38. awesome use live() for events on multiple pages or for things that change containers // in some function $(“#some-tmpl”).tmpl(data).appendTo(“#thing”); // wherever $(“a.childOfThing”).live(“click”,function(e) { e.preventDefault(); doMoreStuff(); }); Sunday, October 17, 2010
  39. 39. AWESOMER! use delegate() for events on one page or always in the same container // in some function $(“#some-tmpl”).tmpl(data).appendTo(“#thing”); // wherever $(“#thing”).delegate( “a.childOfThing”,“click”,function(e) { e.preventDefault(); doMoreStuff(); }); Sunday, October 17, 2010
  40. 40. when the only tool you have is a hammer.. oh wait you have CSS Sunday, October 17, 2010
  41. 41. awesome $(“#some-tmpl”).tmpl(data).appendTo(“#thing”); $(“#childOfThing”).tmplItem().tmpl = $(“#state-two-tmpl”).template(); Sunday, October 17, 2010
  42. 42. AWESOMER! use CSS where possible - it’s faster! $(“#some-tmpl”).tmpl(data).appendTo(“#thing”); $(“#childOfThing”) .removeClass(“stateOne”) .addClass(“stateTwo”); Sunday, October 17, 2010
  43. 43. 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
  44. 44. fast, good, cheap: pick two and a half Sunday, October 17, 2010
  45. 45. faster-ish templates break up the family separate pattern templates from interface templates Always Be Compiling templates = functions Sunday, October 17, 2010
  46. 46. stop sending html Sunday, October 17, 2010
  47. 47. pagination myApp.container = $(“#stuffContainer”); $(“a.showMore”).click(function() { $.get(“/moreStuff”,function(items) { $(“#item-tmpl”) .tmpl(items) .appendTo(myApp.container); }); }); Sunday, October 17, 2010
  48. 48. polling for new data 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”); }); Sunday, October 17, 2010
  49. 49. inline edit $(“#anEditButton”).live(“click”,function() { $(“#thisGuysParent”) .tmplItem() .tmpl = $(“#edit-mode-tmpl”).template(); }); Sunday, October 17, 2010
  50. 50. yo dawg we heard you like plugins Sunday, October 17, 2010
  51. 51. weak $.fn.myPlugin = function(options) { this.html(‘<div class=”’ + options.class + ’”>’ + options.content + ‘<a href=”#”>’ + options.buttonLabel + ‘</a></div>’); ... return this; } Sunday, October 17, 2010
  52. 52. AWESOMER! $.fn.myPlugin = function(options) { this.html($.tmpl(“myTemplate”,options)); ... return this; } Sunday, October 17, 2010
  53. 53. weak $.fn.myPlugin.update = function(newOpts) { this.html(‘<div class=”’ + newOpts.class + ’”>’ + newOpts.content + ‘<a href=”#”>’ + newOpts.buttonLabel + ‘</a></div>’); ... } Sunday, October 17, 2010
  54. 54. AWESOMER! $.fn.myPlugin.update = function(newOpts) { this.tmplItem().data = newOpts; ... } Sunday, October 17, 2010
  55. 55. AWESOMER plugins No more DOM manipulation Don’t have to require a template engine * Sexy updates and redraws Sunday, October 17, 2010
  56. 56. where do templates come from? Sunday, October 17, 2010
  57. 57. in your javascript 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); eeeeek. Sunday, October 17, 2010
  58. 58. in your html <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); Sunday, October 17, 2010
  59. 59. external files if ($.template("commentTmpl").length) { updateComment(comment); } else { $.get("comment-tmpl.js", function(response) { $.template("commentTmpl",response); updateComment(comment); }); } function updateComment(comment) { // rendering happens here } hint: ftw Sunday, October 17, 2010
  60. 60. 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
  61. 61. little external templates put lots of little strings in one file like a constants file e.g. internationalization small patterns available everywhere Sunday, October 17, 2010
  62. 62. what about clients without js? Sunday, October 17, 2010
  63. 63. noscripts srsly? clientside templates on the serverside Sunday, October 17, 2010
  64. 64. two-fer-one Sunday, October 17, 2010
  65. 65. #newtwitter’s doing it Sunday, October 17, 2010
  66. 66. node.js is doing it Sunday, October 17, 2010
  67. 67. takes a little doing have 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 DEMO NAO PLZ now you’re just showing off. Sunday, October 17, 2010
  68. 68. does this template engine come in green? Sunday, October 17, 2010
  69. 69. micro-templates Sunday, October 17, 2010
  70. 70. mustache Sunday, October 17, 2010
  71. 71. jTemplates Sunday, October 17, 2010
  72. 72. pure Sunday, October 17, 2010
  73. 73. 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
  74. 74. i appreciate ya! keep in touch: @garannm / garann@gmail.com demo code: github.com/garann/templates-example Sunday, October 17, 2010

×