Ben Nadel
On User Experience (UX) Design, JavaScript, ColdFusion, Node.js, Life, and Love.
I am the chief technical officer at InVision App, Inc - a prototyping and collaboration platform for designers, built by designers. I also rock out in JavaScript and ColdFusion 24x7.
Meanwhile on Twitter
Loading latest tweet...
Ben Nadel at cf.Objective() 2009 (Minneapolis, MN) with:

Experimenting With The jQuery Template Markup Language (JTML)

By Ben Nadel on

Yesterday, on the YayQuery podcast, the group talked briefly about the jQuery Template proposal. This is the proposal outlining how jQuery might eventually handle templating - the act of rendering output based on a given template and a set of data. I took a brief look at the current proposal and a bunch of the ideas just didn't look right to me (granted I only skimmed the proposal). In my own work, I've gone about templating in a many different ways using everything from node cloning, to textarea values, to HTML comments, to Script tags (my current favorite). While each of these worked in their own way, they all shared a huge limitation - they only worked with a shallow collection of name-value pairs.

 
 
 
 
 
 
 
 
 
 

I come from a ColdFusion background. Now, say what you will about ColdFusion and domain modelling but, ColdFusion is pretty much the ultimate in templating languages. I think the reason ColdFusion works so well is because the rendering tags (CFML) integrate so seamlessly with the markup that they are trying to produce. Because of this, one can easily loop over queries, arrays, and perform conditional rendering logic without any tricky or hard-to-read syntax.

Using ColdFusion as a bit of inspiration, I wanted to see if I could create my own jQuery template rendering language which I will refer to as the "jQuery Template Markup Language" or JTML. The idea behind JTML is that, as with ColdFusion, the JTML tags will integrate seamlessly with the HTML markup as part of a template definition. I started working on this last night, so currently there are only two supported tags:

  • <jtml:if test="condition">
  • <jtml:else [test=""]>
  • </jtml:if>

... and:

  • <jtml:loop index="" key="" collection="">...</jtml:loop>

In the JTML IF tag, for parsing reasons, I chose to use an XSLT-style Test attribute rather than leaving the condition inline. This way, you could use the greater-than symbol within the quotes without confusing the tag parser. The Else tag can also take an optional test condition. The JTML Loop tag can iterate over an array or an object (as the collection). The Index attribute holds the current value while the optional Key attribute holds the array-index or object-key.

If you want to refer to variables within the actual JTML tags, all you have to do is reference them like standard variables. However, if you want to refer to variables outside of the JTML tags, you can ${..} notation to render the value of the given variable. So, for example, to output a girl's name, you could do something like:

  • <span class="name">${girl.name}</span>

I am not sure if I am 100% happy with this direction, but from my preliminary experimentation, I do enjoy having the JTML in tag format. With that said, let's take a look at how this might be used. In the following demo, I am simply rendering a template based on a data object with several nested collections:

  • <!DOCTYPE HTML>
  • <html>
  • <head>
  • <title>jQuery Template Markup Language (JTML) Testing</title>
  • <script type="text/javascript" src="jquery-1.4.2.js"></script>
  • <script type="text/javascript" src="jquery.jtml.js"></script>
  • <script type="text/javascript">
  •  
  • // When the DOM is ready, initialize the script.
  • $(function(){
  •  
  • // Create a new template instance based on the script
  • // template tag.
  • var template = new JTMLTemplate(
  • $( "script.template" )
  • );
  •  
  • // Define the data values to be used to render the
  • // jQuery / html template.
  • var data = {
  • listName: "Girls",
  • items: [
  • {
  • name: "Sarah",
  • attributes: {
  • hair: "Brunette",
  • plump: true,
  • isSexy: true
  • }
  • },
  • {
  • name: "Tricia",
  • attributes: {
  • hair: "Brunette",
  • athletic: true,
  • isSexy: true
  • }
  • },
  • {
  • name: "Lisa"
  • }
  • ]
  • };
  •  
  •  
  • // Create an instance of the rendered template. This
  • // return HTML that we can then turn into a jQuery
  • // collection.
  • var list = $( template.render( data ) );
  •  
  • // Append the list to the page.
  • $( "#output" ).append( list );
  •  
  • // Log rendered template content.
  • console.log( list.html() );
  •  
  • });
  •  
  • </script>
  • </head>
  • <body>
  •  
  • <h1>
  • jQuery Template Markup Language (JTML) Testing
  • </h1>
  •  
  • <div id="output">
  • <!-- To be populated later. -->
  • </div>
  •  
  •  
  • <!--
  • Define the template we are going to use to define the
  • output. Notice that this template expects the following
  • values:
  •  
  • - listName
  • - items
  • -->
  • <script type="text/jtml" class="template">
  •  
  • <div class="list">
  •  
  • <h3>
  • ${listName}
  • </h3>
  •  
  • <!-- Check to see if there are any list items. -->
  • <jtml:if test="(items.length > 0)">
  •  
  • <ul>
  • <!-- Loop over list items. -->
  • <jtml:loop
  • index="girl"
  • key="i"
  • collection="items">
  •  
  • <li id="girl_${i}">
  •  
  • ${girl.name}
  •  
  • <!-- Check for attributes. -->
  • <jtml:if test="('attributes' in girl)">
  •  
  • <ul>
  • <!-- Loop over attributes. -->
  • <jtml:loop
  • index="value"
  • key="attribute"
  • collection="girl.attributes">
  •  
  • <li>
  • ${attribute} : ${value}
  • </li>
  •  
  • </jtml:loop>
  • </ul>
  •  
  • <jtml:else>
  •  
  • <br />
  • <em>No attributes</em>.
  •  
  • </jtml:if>
  • </li>
  •  
  • </jtml:loop>
  • </ul>
  •  
  • <jtml:else>
  •  
  • <p>
  • <em>There are no list items at this time.</em>
  • </p>
  •  
  • </jtml:if>
  •  
  • </div>
  •  
  • </script>
  •  
  • </body>
  • </html>

As you can see, I am using a Script tag to define my JTML template. The content of the template consists of standard HTML markup seamlessly integrated with JTML tags. Right now, the JTML tags are name-spaced with the "jtml:" prefix; I am not sure if I will keep this in the future, but for now, this seemed like an easy way to differentiate the types of markup tags.

In the Javascript, you'll notice that I am defining a Data object with dually-nested collections; the data contains an array of items (girls) and each item may or may not contain a list of attributes. Using the JTML tags, I can easily loop over and render each girl as well as check for the existence of optional attributes. When I run the above code, I get the following page output:

 
 
 
 
 
 
jQuery Template Markup Language (JTML) Testing. 
 
 
 

As you can see, the JTML engine was able to render the jQuery template based on the complex and nested data object.

When I have some time, I'll go back and read the jQuery Template proposal more thoroughly; but for now, I really like playing around with this raw idea. I think having rendering tags (JTML) easily integrate with the HTML markup is key to creating an effective templating engine. Right now, I am not sure what other kinds of tags I'd like to implement in the jQuery Template Markup Language. If you have any suggestions, please let me know.




Reader Comments

No mention of Spry at all? :) I know it doesn't get much respect, and I myself no longer use it, but it really deserves credit for promoting this idea I think. Nothing does "load crap and display on page" as easily or direct as Spry I think.

Reply to this Comment

@Ricardo,

I figured there was stuff out there already - but it's always more fun to re-invent the wheel, if for no other reason than to get the creative juices flowing.

Last night, when I started thinking about this, I thought about using XSLT; but, after a minute or two of research, it looked like creating XML objects was overly complex in the various browsers. Plus, while I love XML with an intensity, I have to say that I have never been too pleased with XSLT.

I thought that this approach, JTML, was a nice mix of tags without having to worry about XML parsing.

Reply to this Comment

@Raymond,

It's funny you mention that - when I was first thinking about this last night, I wanted to look up SPRY. I even went to the labs.adobe.com site; but I found it really hard to find an example of a template rendering style scenario.

If you can point me in the right direction, I'd love to take a look. I've literally never ran SPRY before, so I didn't even know where to start.

Reply to this Comment

@Raymond,

Cool - I'll take a look-see at lunch. And sometimes, things are just nice to force yourself to think in a different way. Who knows where the inspiration will lead.

Plus, I got to give props to ColdFusion :)

Reply to this Comment

Yes, you're right, it's good to just try to think things through and start over fresh.
And BTW, using JSON instead of XML is definitely a breakthrough!

Reply to this Comment

I assume this is using a RexExp ${key} replace methodology similar to the one found in corMVC? My worry with RexExp (especially client-side) is performance. The (usually) necessary live() bindings on top of that could really start eating up cycles. Then again, I can be performance obsessive to my own detriment so I may be worrying about issues that don't exist in practical application.

I'm going to try and integrate this into my current project (which itself is based upon a heavily bruised version of corMVC) and see how it goes.

Oh, I have to agree with you about XSLT. I just feels so bloody 'heavy'. That might be because I've never given it the time it deserves, but like SOAP you have to lug around soooo much verbage. <jtml:> looks tiny and elegant in comparison.

Reply to this Comment

@Ben Well you have a Model (your list of models *wink* *wink* *nudge* *nudge*) and you have a template (which is basically the view), and whatever would put the two together and render it within the template would be your Controller.

Snook on A List Apart does kind of the same thing what with his replacement of values contained in ${} blocks.

However you seem to have taken this a bit further by adding tags and such.

The only problem that I see with all of this is when the google SEO comes through to read your site, there's nothing but JSON there, so I don't quite understand how the spider is supposed to pick it up.

(Unless of course on your server side you detect that a spider is looking at your site, and send it something else)

I've actually been looking for a solution to that problem ever since I saw Snook's JS MVC solution on A List Apart.

Reply to this Comment

@Grant,

I tried to optimize for performance as much as I could. Yes, it does use RegExp to replace out the ${..}, but only the first time the template compiles. It actually compiles the template down to a (new Function()), replacing out the variable place holders with actual Javascript variables.

There's some per-execution compiling because it needs to create the function in the context of the data map, so it actually ends up running the pre-compiled function as a sub-function of an on-the-fly function that locally-scopes the mapped keys. It's a bit hacky, but it's the only way I could figure out how to allow the function to be able to reference the data keys without having to scope them.

I even considered running it inside its own iFrame, but couldn't get that to work.

Hopefully, I'll have some time tonight to actually post the underlying code to the Project page.

@Andrew,

Ah, yes yes, I see what you mean. Yeah, I think this is the basic idea behind a lot of the rendering engines; even in Groovy which uses $varName as a "GString" place holder.

Jon Snook is a pretty brilliant guy; I will have to give the article you mentioned a read - I am sure there is some goodness I can borrow from it.

As far as the SEO stuff, I assume if you're using templates, you've already made the call that this data is gonna be loaded remotely, which would hurt SEO. I think this kind of stuff has more use for AJAX-returned data than inline data (where it's probably easier to render the HTML on the server anyway).

Reply to this Comment

@Ben Yeah, what you said about the SEO makes sense.

I think if you read though the comments in Snook article you'll find alot of people saying what I said, and it looks to me like Snook might not have made the fact that it was only intended for rendering ajax retrieved json data (or alot of people didn't read it). Rendering the entire page that way would definitely botch up the SEO.

You might want to put that in your article and tell Snook to put it in his.

(Although Snook's isn't jQuery based)

Reply to this Comment

And you got to mention the YayQuery podcast which did a shout out to you yesterday, right? Well played, sir, well played. ;)

(plus, gotta love you calling plump sexy. Sarah and the rest of us curvy girls send you a big thanks :D)

Reply to this Comment

Post A Comment

You — Get Out Of My Dreams, Get Into My Comments
Live in the Now
Oops!
Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.