{"id":1095,"date":"2012-05-10T23:34:39","date_gmt":"2012-05-10T21:34:39","guid":{"rendered":"http:\/\/doanduyhai.wordpress.com\/?p=1095"},"modified":"2012-05-10T23:34:39","modified_gmt":"2012-05-10T21:34:39","slug":"html-templating-with-jquery","status":"publish","type":"post","link":"https:\/\/www.doanduyhai.com\/blog\/?p=1095","title":{"rendered":"HTML templating with jQuery"},"content":{"rendered":"<p>In this short article, we&#8217;ll see some techniques to generate DOM elements and section using jQuery and its chaining feature.<\/p>\n<p><!--more--><\/p>\n<h1>I Dynamic DOM elements creation<\/h1>\n<p> There are 2 techniques out there to create dynamic DOM elements.<\/p>\n<p>1. Using the <em>createElement()<\/em> method on the <strong>Document<\/strong> standard oject: <\/p>\n<pre>\nvar myDiv = document.createElement(\"div\");\nvar mySpan = document.createElement(\"span\");\nmySpan.createTextNode(displayedText);\nmyDiv.appendChild(mySpan);\n<\/pre>\n<p>2. Using jQUery<\/p>\n<pre>\nvar myDiv = $('div').append(($('span').html(displayText));\n<\/pre>\n<p> Clearly the second method is better and cleaner.  However this technique is suitable only for occasionnal dynamic DOM creation. If you need to create iterable items (like a table or a list of items) with dynamic data, it&#8217;ll become quickly a nightmare<\/p>\n<p>&nbsp;<\/p>\n<h1>II HTML templating with jQuery<\/h1>\n<h3>A) The idea<\/h3>\n<p> Here is a very common use case: you are designing a <strong>user search page<\/strong>. There is a search form with various parameters. Below the search section is the result section where you display all found users in a table.<\/p>\n<p> In the old style architecture, a click on &#8220;<strong>Search<\/strong>&#8221; button will submit the form to the server, which will then execute the query and build the result table and render the response page. All the job is done server-side.<\/p>\n<p> With <strong>RESTfull <\/strong>architecture, the server only takes care of the DB querying and will return a list of <strong>JSON objects<\/strong> as results. The client-side is responsible for the data formatting. There &#8220;<strong>HTML templating<\/strong>&#8221; comes into play.<\/p>\n<p> The idea is to create a template row representing a result and hide it at the end of the page:<\/p>\n<pre class=\"brush: xml; highlight: [4,14]; title: ; wrap-lines: false; notranslate\" title=\"\">\n&amp;lt;div&amp;gt;\n\t&amp;lt;form id=&amp;quot;searchForm&amp;quot;&amp;gt;\n\t\t...\n\t\t&amp;lt;button type=&amp;quot;submit&amp;quot; onclick=&amp;quot;doSearch()&amp;quot;&amp;gt;Search&amp;lt;\/button&amp;gt;\n\t\t...\n\t&amp;lt;\/form&amp;gt;\n\t&amp;lt;section id=&amp;quot;resultArea&amp;quot;&amp;gt;\n\t\t&amp;lt;table id=&amp;quot;resultTable&amp;quot;&amp;gt;\n\t\t\t&amp;lt;thead&amp;gt;...&amp;lt;\/thead&amp;gt;\n\t\t\t&amp;lt;tbody&amp;gt;&amp;lt;\/tbody&amp;gt;\n\t\t&amp;lt;\/table&amp;gt;\n\t&amp;lt;\/section&amp;gt;\n&amp;lt;\/div&amp;gt;\t\n&amp;lt;div id=&amp;quot;templates&amp;quot; style=&amp;quot;display:none;&amp;quot;&amp;gt;\n\t&amp;lt;tr id=&amp;quot;rowTemplate&amp;quot;&amp;gt;\n\t\t&amp;lt;td class=&amp;quot;name&amp;quot;&amp;gt;Name&amp;lt;\/td&amp;gt;\n\t\t&amp;lt;td class=&amp;quot;age&amp;quot;&amp;gt;Age&amp;lt;\/td&amp;gt;\n\t\t&amp;lt;td class=&amp;quot;skills&amp;quot;&amp;gt;Java, C#, Python&amp;lt;\/td&amp;gt;\n\t\t&amp;lt;td class=&amp;quot;xp&amp;quot;&amp;gt;5 years&amp;lt;\/td&amp;gt;\n\t&amp;lt;\/tr&amp;gt;\n\t\n\t&amp;lt;span id=&amp;quot;someOtherTemplate&amp;quot;&amp;gt;\n\t\t...\n\t\t...\n\t&amp;lt;span&amp;gt;\n&amp;lt;\/div&amp;gt;\n<\/pre>\n<p> As shown above, all the DOM element templates are nested inside a div container with <strong><em>style=&#8221;display:none;&#8221;<\/em><\/strong> so it will not be visible on the page.<\/p>\n<p> The same div can contain several template elements, like our template row for search result or any other templates. <strong>You need to give them a unique id so they can be easily fetched using jQuery selector<\/strong>.<br \/>\n&nbsp;<\/p>\n<h3>B) Implementation<\/h3>\n<p> Now let&#8217;s see how we can format result row upon reception of the JSON data from server. Let&#8217;s assume that the returned data is a list of JSON objects representing each an user details:<\/p>\n<pre>\n{\n\t\"name\": \"John Skit\",\n\t\"age\": \"29\",\n\t\"skills\": \"Java, Groovy, HTML5\",\n\t\"xp\": \"7 years\"\t\n}\n<\/pre>\n<pre class=\"brush: jscript; title: ; wrap-lines: false; notranslate\" title=\"\">\nfunction doSearch()\n{\n\t$.ajax({\n\t\ttype: 'GET',\n\t\turl:  '\/search',\n\t\tdataType: 'json',\n\t\tsuccess: function(data)\n\t\t{\n\t\t\t$.each(data, function(index,user)\n\t\t\t{\n\t\t\t\t$('#rowTemplate').clone().attr('id','')\n\t\t\t\t.find('.name').html(data.name).end()\n\t\t\t\t.find('.age').html(data.age).end()\n\t\t\t\t.find('.skills').html(data.skills).end()\n\t\t\t\t.find('.xp').html(data.xp).end().\n\t\t\t\t.appendTo('#resultTable tbody');\n\t\t\t});\n\t\t}\n\t});\n}\n<\/pre>\n<p> In the ajax success function, upon reception of the JSON data set, we iterate through the &#8220;<strong>data<\/strong>&#8221; list. For each user JSON we:<\/p>\n<ol>\n<li>clone the <strong>#rowTemplate<\/strong><\/li>\n<li>clear its id<\/li>\n<li>find each row column by its class<\/li>\n<li>fill in its HTML content with JSON data<\/li>\n<li>append the whole row to the body of <strong>#resultTable<\/strong><\/li>\n<\/ol>\n<p> That&#8217;s pretty simple. The job is done with a jQuery chain using <strong>end()<\/strong> method to go back and forth to the row element (for details on <strong>jQuery chaining<\/strong>, check my <a href=\"http:\/\/doanduyhai.wordpress.com\/2012\/05\/10\/jquery-chaining\/\" title=\"jQuery wrapped-set\u00a0chaining\" target=\"_blank\">previous post<\/a>).<\/p>\n<p> Please notice that at step 2, <strong>we need to clear the id of the cloned element otherwise we&#8217;ll end up having several rows with the same id in the DOM<\/strong>, big trouble!<\/p>\n<p> Of course, the example is quite straightforward because the logic is minimalist. If you have complex logics with if\/else if blocks involved, <strong>all the jQuery chaining beauty is gone!<\/strong><\/p>\n<pre class=\"brush: jscript; highlight: [12]; title: ; wrap-lines: false; notranslate\" title=\"\">\nfunction doSearch()\n{\n\t$.ajax({\n\t\ttype: 'GET',\n\t\turl:  '\/search',\n\t\tdataType: 'json',\n\t\tsuccess: function(data)\n\t\t{\n\t\t\tvar row;\n\t\t\t$.each(data, function(index,user)\n\t\t\t{\n\t\t\t\trow =$('#rowTemplate').clone().attr('id','');\n\n\t\t\t\trow.find('.name').html(data.name).end()\n\t\t\t\t.find('.age').html(data.age);\n\n\t\t\t\t\/\/ Age discrimination\n\t\t\t\tif(data.age &amp;gt; 50) \n\t\t\t\t{\n\t\t\t\t\trow.find('.age').addClass('oldDuffer'); \n\t\t\t\t}\n\t\t\t\t\n\t\t\t\trow.find('.skills').html(data.skills).end()\n\t\t\t\t.find('.xp').html(data.xp);\n\n\t\t\t\t\/\/ XP highlighting\n\t\t\t\tif(data.xp &amp;lt; 3) \n\t\t\t\t{\n\t\t\t\t\trow.find('.xp').addClass('junior'); \n\t\t\t\t}\n\n\t\t\t\trow.appendTo('#resultTable tbody');\n\t\t\t});\n\t\t}\n\t});\n}\n<\/pre>\n<p>Note: I&#8217;ve seen some HTML templating solutions based on <a href=\"https:\/\/github.com\/janl\/mustache.js\" title=\"Mustache.js\" target=\"_blank\">Mustache<\/a>. It&#8217;s quite nice. The only downside is the logic-less (no if\/else logic) nature of this framework. For the above example it won&#8217;t work. Furthermore, in Mustache, there is too much &#8220;mustaches&#8221; (<strong>{{<\/strong>variable<strong>}}<\/strong>)  for my liking. There are even triple mustaches to render unescaped HTML: <strong>{{{name}}}<\/strong> !!!<\/p>\n<p>&nbsp;<br \/>\n&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this short article, we&#8217;ll see some techniques to generate DOM elements and section using jQuery and its chaining feature.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[27,13],"tags":[],"_links":{"self":[{"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/1095"}],"collection":[{"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1095"}],"version-history":[{"count":0,"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/1095\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1095"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1095"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1095"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}