HTML templating with jQuery

In this short article, we’ll see some techniques to generate DOM elements and section using jQuery and its chaining feature.

I Dynamic DOM elements creation

There are 2 techniques out there to create dynamic DOM elements.

1. Using the createElement() method on the Document standard oject:

var myDiv = document.createElement("div");
var mySpan = document.createElement("span");
mySpan.createTextNode(displayedText);
myDiv.appendChild(mySpan);

2. Using jQUery

var myDiv = $('div').append(($('span').html(displayText));

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’ll become quickly a nightmare

 

II HTML templating with jQuery

A) The idea

Here is a very common use case: you are designing a user search page. 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.

In the old style architecture, a click on “Search” 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.

With RESTfull architecture, the server only takes care of the DB querying and will return a list of JSON objects as results. The client-side is responsible for the data formatting. There “HTML templating” comes into play.

The idea is to create a template row representing a result and hide it at the end of the page:

<div>
	<form id="searchForm">
		...
		<button type="submit" onclick="doSearch()">Search</button>
		...
	</form>
	<section id="resultArea">
		<table id="resultTable">
			<thead>...</thead>
			<tbody></tbody>
		</table>
	</section>
</div>	
<div id="templates" style="display:none;">
	<tr id="rowTemplate">
		<td class="name">Name</td>
		<td class="age">Age</td>
		<td class="skills">Java, C#, Python</td>
		<td class="xp">5 years</td>
	</tr>
	
	<span id="someOtherTemplate">
		...
		...
	<span>
</div>

As shown above, all the DOM element templates are nested inside a div container with style=”display:none;” so it will not be visible on the page.

The same div can contain several template elements, like our template row for search result or any other templates. You need to give them a unique id so they can be easily fetched using jQuery selector.
 

B) Implementation

Now let’s see how we can format result row upon reception of the JSON data from server. Let’s assume that the returned data is a list of JSON objects representing each an user details:

{
	"name": "John Skit",
	"age": "29",
	"skills": "Java, Groovy, HTML5",
	"xp": "7 years"	
}
function doSearch()
{
	$.ajax({
		type: 'GET',
		url:  '/search',
		dataType: 'json',
		success: function(data)
		{
			$.each(data, function(index,user)
			{
				$('#rowTemplate').clone().attr('id','')
				.find('.name').html(data.name).end()
				.find('.age').html(data.age).end()
				.find('.skills').html(data.skills).end()
				.find('.xp').html(data.xp).end().
				.appendTo('#resultTable tbody');
			});
		}
	});
}

In the ajax success function, upon reception of the JSON data set, we iterate through the “data” list. For each user JSON we:

  1. clone the #rowTemplate
  2. clear its id
  3. find each row column by its class
  4. fill in its HTML content with JSON data
  5. append the whole row to the body of #resultTable

That’s pretty simple. The job is done with a jQuery chain using end() method to go back and forth to the row element (for details on jQuery chaining, check my previous post).

Please notice that at step 2, we need to clear the id of the cloned element otherwise we’ll end up having several rows with the same id in the DOM, big trouble!

Of course, the example is quite straightforward because the logic is minimalist. If you have complex logics with if/else if blocks involved, all the jQuery chaining beauty is gone!

function doSearch()
{
	$.ajax({
		type: 'GET',
		url:  '/search',
		dataType: 'json',
		success: function(data)
		{
			var row;
			$.each(data, function(index,user)
			{
				row =$('#rowTemplate').clone().attr('id','');

				row.find('.name').html(data.name).end()
				.find('.age').html(data.age);

				// Age discrimination
				if(data.age > 50) 
				{
					row.find('.age').addClass('oldDuffer'); 
				}
				
				row.find('.skills').html(data.skills).end()
				.find('.xp').html(data.xp);

				// XP highlighting
				if(data.xp < 3) 
				{
					row.find('.xp').addClass('junior'); 
				}

				row.appendTo('#resultTable tbody');
			});
		}
	});
}

Note: I’ve seen some HTML templating solutions based on Mustache. It’s quite nice. The only downside is the logic-less (no if/else logic) nature of this framework. For the above example it won’t work. Furthermore, in Mustache, there is too much “mustaches” ({{variable}}) for my liking. There are even triple mustaches to render unescaped HTML: {{{name}}} !!!

 
 

Advertisements

About DuyHai DOAN
Cassandra Technical Evangelist. LinkedIn profile : http://fr.linkedin.com/pub/duyhai-doan/2/224/848. Follow me on Twitter: @doanduyhai for latest updates on Cassandra

One Response to HTML templating with jQuery

  1. romaintaz says:

    The template is a good solution to have a clear vision of what the HTML will look like at the end.

    However, an interesting point is to have a look on the performances. You should try to have a benchmark on the 2 following solutions (using jQuery) :

    1. Using the $.clone() methods, with all the find() methods, as shown in your example.
    2. Creation of all the HTML elements using jQuery.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: