Had a little time to kill between tasks a few weeks ago, and Googled to see if I could find a solution to all these dreaded string-concatenations I was finding throughout pieces of our Javascript codebase at work. They were piecing together HTML code (in strings) and attaching objects’ data into the HTML. I stumbled upon EJS (http://embeddedjs.com) and fell in love instantly!
It allows you to create HTML templates, with Javascript placeholders, not unlike Ruby on Rails or ASP.Net. Their main page has a great, little interactive demo. Go check it out, and come back. I’ll probably still be here.
…
Back? Great! So now you’re probably a little excited if you haven’t seen that before. Otherwise, humor me for a bit while I stay geeked-out over this.
It is such a simple, and elegant solution to the problems I was griping to myself about, that I couldn’t wait to test it out for myself. And at the same time, I thought I’d write up this little post about it, comparing jQuery as a templating medium, vs EJS. Here we go.
To start, we need some Javascript objects, so I’ve created a simple array of three simple “product” objects.
products:
var products = [
{
id:0,
desc:"product 0",
price: 10.50
},
{
id:1,
desc:"product 1",
price: 1.25
},
{
id:2,
desc:"product 2",
price: 5.60
}
];
Now that I’ve got some data to work with, let’s create a list to show off the data in HTML. First, we’ll use jQuery. This example is really trivial, but it’s just an example, so I’m not going to split-hairs here. First I grab the UL that will hold the HTML once I’m through adding my product data, then for each product in my products array, I create an LI, and add some attributes/text to them.
jQuery:
var jquery_products = $("#jquery_products");
$.each(products,function(){
var li = $("<li/>").addClass("product");
var a = $("<a/>").appendTo(li);
a.attr("href","/product/"+this.id);
a.html(this.desc + " ($"+this.price+")");
jquery_products.append(li);
});
Pretty simple, eh? And that will output the following HTML:
<ul id="jquery_products"> <li class="product"> <a href="/product/0">product 0 ($10.5)</a> </li> <li class="product"> <a href="/product/1">product 1 ($1.25)</a> </li> <li class="product"> <a href="/product/2">product 2 ($5.6)</a> </li> </ul>
Now, let’s see how EJS stacks up. First, I grab the UL that will hold the HTML that will be output from my EJS template, then, I create a new EJS template, pointing to my template file, product.ejs, and then render the contents using the array of products.
EJS:
var ejs_products = document.getElementById("ejs_products");
var html = new EJS({url: 'scripts/templates/product.ejs'}).render(products);
ejs_products.innerHTML = html;
But we’re only half-done. We now need to define product.ejs, which is below:
product.ejs:
<% for(var i=0; i < this.length; i++) {%>
<!-- Get the current product, "this" is the products array that was passed in-->
<% var product = this[i]; %>
<li class="product">
<%= link_to(product.desc + " ($"+product.price+")", "/product/"+product.id) %>
</li>
<% } %>
Nice and clean. And very maintainable. The output is the same as the jQuery output:
<ul id="ejs_products"> <li class="product"> <a href="/product/0">product 0 ($10.5)</a> </li> <li class="product"> <a href="/product/1">product 1 ($1.25)</a> </li> <li class="product"> <a href="/product/2">product 2 ($5.6)</a> </li> </ul>
I definitely will be using EJS from now on as my Javascript templating framework. jQuery works just fine, but I believe for maintainability’s sake, I will keep my HTML separate from my Javascript as much as possible. It just “feels” right.
The only caveat I have is that you need to make sure you’ve got the right path to your EJS template file. Since your Javascript runs on the current page, and therefore, that current page’s URL, you’ll need to make sure you’ve got the right absolute, or relative path specified to reach the EJS template file. The best thing you can probably do is either always use the absolute path, “/scripts/path_to_template_files/my_template.ejs”, or, create a javascript variable in your page somewhere that always points to the root of your website, and append your template file directory from there.
var base_url = "http://mywebsite.com";
//...snip
var html = new EJS({url:base_url+"/scripts/templates/my_template.ejs"}).render(data);
{ 1 trackback }
{ 2 comments… read them below or add one }
Thanks for writing this quick tutorial!
Have you tried non-trivial EJS scripts on slower javascript implementations? It seems like the performance of your webapp will then vary based on the user’s machine (rather than your server).
I have not tried it on anything but modern browsers, but I wouldn’t anticipate it being a burden for the client to render the HTML.