BIGREDSWITCH Push it. You know you want to.

jQuery Templating Plugin

I wanted to take a look at the templating plugin included in the jQuery distribution (for some reason, there is no documentation of it on jquery.com, this is the same templating plugin included in ReinH/Katz autocomplete plugin here). It’s not the best documented plugin but it’s short so should be quick to figure out.

Basically, what this plugin does is take a block of text and interprets it as a template. What is a template? Well, for this plugin, think about JSP or ASP. I.e., executable code between special characters interspersed with HTML. So for example:

23       <% $(arr).each(function() { %>
24         <a href="<%= this.url %>"><%= this.text %></a>
25       <% }); %>

This code uses JSP like syntax where executable code is between ‘<%’ and ‘%>’ tags. And variable expansion uses the ‘<%=’ and ‘%>’; this means that the code inside the variable expansion gets expanded to the value in place (see this.url and this.text in example above.) Where does the arr variable come from? This is passed in as a context parameter to the completed template. Whoa, last 2 sentences need to be explained a little more. Look at the full HTML example distributed in the plugin itself:

 1 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 2 <html>
 3   <head>
 4     <meta http-equiv="Content-type" content="text/html; charset=utf-8">
 5     <title>Templating</title>
 6     <script src="../jqueryjs/jquery/dist/jquery.js"></script>
 7     <script src="../jqueryjs/plugins/templating/jquery.templating.js"></script>
 8     <script type="text/javascript">
 9       jQuery(function($) {
10         $.pageTemplates = {};
11         $("script[type=text/x-jquery-template]").each(function() {
12           $.pageTemplates[this.title] = $.makeTemplate(this.innerHTML, "<%", "%>");
13           $("body").append($.pageTemplates["template1"]({arr: 
14             [{url: "http://www.yehudakatz.com", text: "Yehuda's site"},
15              {url: "http://www.gweezlebur.com", text: "Ivey's site"}]
16           }));
17         });
18       });
19     </script>
20   </head>
21   <body>
22     <script type="text/x-jquery-template" title="template1">
23       <% $(arr).each(function() { %>
24         <a href="<%= this.url %>"><%= this.text %></a>
25       <% }); %>
26     </script>
27     <a href="foo" rel="#myTemplate" class="updateTemplate">Click</a>
28   </body>
29 </html>

You can see the template itself in lines 22-26 cleverly embedded inside a script tag with a custom type attribute. Now look at the lines 11-17. Line 12 takes the template text itself and creates a template function. Yes, $.makeTemplate, the public templating plugin method, returns a function. That function is then called with a context parameter (a hash) and the template is evaluated. Note that the arr variable is passed into the template function on line 13.

Aight! What do you think of that? At first, I was like what the heck? but looking at it a few times now and it’s rather natural. Let’s look at the actual plugin next. It’s only 25 lines of formatted code:

 1 // Copyright Yehuda Katz
 2 // with assistance by Jay Freeman
 3 // You may distribute this code under the same license as jQuery (BSD or GPL)
 4 (function ($) {
 5   $.makeTemplate = function (template, begin, end) {
 6     var rebegin = begin.replace(/([\]{}[\\])/g, '\\$1');
 7     var reend = end.replace(/([\]{}[\\])/g, '\\$1');
 8 
 9     var code = "try { with (_context) {" +
10       "var _result = '';" +
11         template
12           .replace(/[\t\r\n]/g, ' ')
13           .replace(/^(.*)$/, end + '$1' + begin)
14           .replace(new RegExp(reend + "(.*?)" + rebegin, "g"), function (text) {
15             return text
16               .replace(new RegExp("^" + reend + "(.*)" + rebegin + "$"), "$1")
17               .replace(/\\/g, "\\\\")
18               .replace(/'/g, "\\'")
19               .replace(/^(.*)$/, end + "_result += '$1';" + begin);
20           })
21           .replace(new RegExp(rebegin + "=(.*?)" + reend, "g"), "_result += ($1);")
22           .replace(new RegExp(rebegin + "(.*?)" + reend, "g"), ' $1 ')
23           .replace(new RegExp("^" + reend + "(.*)" + rebegin + "$"), '$1') +
24       "return _result;" +
25     "} } catch(e) { return '' } ";
26 
27     return new Function("_context", code);
28   };
29 })(jQuery);

Very nicely written I would have to say.

Lines 6-7 munges the begin and end tags to be regualar expression friendly.

The next statement (lines 9-25) creates the code block. Note that the code block starts with a with (_context) { and returns the code block on line 27 with return new Function(”_context”, code). If you forgot what the with statement in JavaScript does, take a look here. There’s a bunch of regular expressions that I’m sure you can figure out (nothing too difficult), but a quick way to see what this is doing is adding the line ‘alert(code)‘ at line 26. Ahh, should be obvious now.

Doing this for the example, gives the text below and it becomes obvious:

try {
  with (_context) {
    var _result = '';
    _result += '       ';
    $(arr).each(function() {
      _result += '         <a href="';
      _result += ( this.url );
      _result += '">';
      _result += ( this.text );
      _result += '</a>       ';
    });
    _result += '     ';
    return _result;
  }
} catch(e) { return '' }

So to recap a few points:


No Comments Yet


There are no comments yet. You could be the first!

Leave a Comment

Leningrad Cowboys & Red Army Choir jQuery Autocomplete Plugin