Wednesday, February 24, 2010

Falling in line to the (micro)templating frenzy

A few weeks ago I would've laughed in your face if you told me I was gonna fall in line to the templating frenzy that seems to be spreading like a virus between coders. Now - one way or the other - I seem to be infected.

I recently tackled the challenge of generating a DTO layer (including mapping logic) from WCF service client using T4 (with no editor whatsoever - don't get me started). I honestly thought I was gonna blog about that sooner or later but then I immediately got shuffled around like a puppet to some front-end work (I am talking web here) and faced the lame-ass ordinary challenge of dynamically injecting repetitive structures into a given page in response to a given event (click-click-click-click ... click).

Coming from that T4 work, templating obviously came to mind as a way not to get bored: wouldn't it be great if there was something like T4 for js? It sounded crazy at first, but I started looking into it and immediately found the John Resig Micro-Templating engine.

There was no way I was gonna pass on that and, to be honest, the only alternatives were pretty lame:
  • implement your own templating engine 
  • shamelessly hard-code the markup to inject in your .js functions (as I always did before)
So I started playing with it and managed to stumble upon the Rick Strahl variation to it, which actually uses T4 syntax (it sure doesn't look like a coincidence) and also has a nice addition for error handling.

Anyway, this is getting too long: here's an example where I am adding divs with a bunch of input fields to a container, ids are generated at runtime depending on how many divs we have in there. It's ugly as fuck it gets, but it drags the message across (I think).

Let's start
you need to shove the templating engine function in a file. I called it templating.js and you can just copy paste whatever Rick Strahl has on his article. Once you've done that, add templating.js and jQuery.js as external script files to your html.

Once you have that in place, it's time to populate you jQuery init function and add your micro-template (the micro-template is added in a script element defined as text). This should be pretty straightforward if you read the comments:
<!-- all this goes into the head section --> <script type="text/javascript"> $(document).ready(function() { //IDs for the first div var idsArray = { divId: "div_0", input1Id: "input1_0", input2Id: "input2_0" }; // logic to add the first div function onLoad() { var templ = $("#myRepeaterTemplate").html(); var parsed = parseTemplate(templ, idsArray); $("#myTarget").html(parsed); } // inject the first div onLoad(); // Add onclick handler to button w/id addBtn $("#addBtn").click(function() { //1. count how many divs var size = $("#myTarget > div").size(); //2. generate name value pairs var myArray = { divId: "div_" + size, input1Id: "input1_" + size, input2Id: "input2_" + size }; //3. invoke parseTemplate var templ = $("#myRepeaterTemplate").html(); var parsed = parseTemplate(templ, myArray); //4. append $("#myTarget").append(parsed); }); }); </script> <script id="myRepeaterTemplate" type="text/html"> <div id="<#= divId #>" > <input id="<#= input1Id #>" type="text" value="some input" /> <input id="<#= input2Id #>" type="text" value="some input" /> </div> </script>

And the following is what you need in the body of the page for this to work:

<div id="myTarget">
   <p>this stuff should be wiped on load</p>
</div>
<input id="addBtn" type="button" value="Add" />

This is just a very basic example that should be suitable when you just want to inject some markup given a template, but you can put actual js logic into the template. For a nice example of that have a look at this nice example here.

I am a lazy-ass late adopter, and if I am using this stuff  (talking about the templating frenzy in general) - it generally means it can't be ignored much longer. Do so at your own risk.

No comments: