Browser-Side Templating - Ajax Patterns

Browser-Side Templating

From Ajax Patterns

Evidence: 1/3

Tags: Pages Presentation Render Template Transform View


Contents

In A Blink

Diagram A little template code


Technical Story

Devi has just received a request to add more details to the user profile. The original version takes an XML document about the user and renders it all using a jungle of Javascript code, a function that accumulates a big HTML string amid if-then conditions and loops. Devi decides to refactor the Javascript to use a Browser-Side Template, isolating the HTML generation. As a result, introducing the new content becomes trivial.


Problem

How can you separate presentation from logic?


Forces

  • Generating HTML in the browser is a good thing if you wish to isolate all presentation logic in the one tier.
  • Often, the nature of the HTML is dynamic, depending on browser state and incoming responses from the server.
  • To render context-specific information within the browser, you need to rely on a dynamic mechanism. It's not feasible to just set an element's innerHTML property to point to a static HTML page.
  • Code gets complex and error-prone when you mix HTML generation with application logic. Javascript is not well-suited to programmatically building up HTML strings.


Solution

Produce browser-side templates and call on a suitable browser-side framework to render them as HTML. The template contains standard HTML and allows context variables to be substituted in at rendering time, which gives it more flexibility than a static HTML page. In addition, you can also intersperse Javascript code. For instance, you could generate an HTML table by running a loop, one iteration for each row.

The templating idea has been used for a long time on the web, with tools like Perl's HTML::Mason, PHP, Active Server Pages (ASPs), Java Server Pages (JSPs). All of them are syntactic sugar of the "killer app" variety. That is, they technically add no new functionality, but they make life a whole lot easier for web developers. In the Java world, the standard alternative to JSPs is servlets. Here's how you'd write a message in a servlet:

  package com.example.hello;
 
  import java.io.IOException;
  import java.io.PrintWriter;
  import javax.servlet.ServletException;
  import javax.servlet.http.HttpServlet;
  import javax.servlet.http.HttpServletRequest;
  import javax.servlet.http.HttpServletResponse;
 
  public class HelloServlet extends HttpServlet {

    protected void doGet(HttpServletRequest request,
                         HttpServletResponse response)
              throws ServletException, IOException {

      response.setContentType("text/html");
      PrintWriter out = response.getWriter();
      out.println("<html>");
      out.println("<head><title>Hi Everyboddeee!</title></head>");
      out.println("<body>");
      out.println("<h1>Howdy</h1>");
      out.println("  Your name is \"" + request.getAttribute("name") + "\".");
      out.println("</body></html>");
      out.close();
    }
  }

Not pretty. There are printing commands all over the place, escaping special characters, quote marks, error-handling. What happened to the simplicity of HTML? Likewise, the Java logic is obscured by the heavy presence of HTML generation. In short, code like this is undesirable because it mixes presentation with logic.

The following JSP, using the standard JSTL library, achieves the same thing in a more lucid, maintainable, style.

  <%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
  <html>
  <head><title>Hi Everyboddeee!</title></head>
  <body>
    Your name is <c:out value="$name" />.
  </body>
  </html>

With many Ajax applications, it's deja vu. Often, the browser receives an XMLHttpRequest Call response from a Semantic Service, in the form of a complex data structure - XML Message, JSON Message, or customised format. At this point, it's over to the browser to render it as HTML, so server-side templates are not an option. A common approach is to manually traverse the structure programmatically and create some HTML to be injected via some element's innerHTML property. The old servlet-style "bucket of print statements" recurs: Javascript is used to build up a big chunk of HTML, as messy as it was on the server-side.

The solution here recapitulates in Javascript what all those server-server side templating frameworks offer. A templating framework, while not immensely difficult to implement, is probably not the sort of thing you'd want to write yourself. This pattern, then, is only made possibly by the fact that frameworks already exist. The frameworks are discussed in the examples below, but here is a quick example of a template. The following Javascript template - in Ajax Pages format, will run a loop:

    <ul>
  <%
      for (i=0; i<context.names.length; i++) {
        var name = conext.names[i];
  %>
        <li> <%= name %> </li>
  <%
      }
  %>
    </ul>

The Javascript template is in similar format to the JSP above, and follows standard conventions of templates. That is:

  • Any code is contained inside <% and %> tags.
  • Any expression to be substituted in the HTML is contained inside <%= and %> tags.

To apply the template, you create a processor and pass it a context.

 var ajp = new AjaxPages();
 ajp.load("template.ajp");
 var processor = ajp.getProcessor();
 element.innerHTML = processor(context);


Decisions

Will the template include any code? How much?

Code in templates is somewhat frowned upon because it defeats the purpose of templates as a place to isolate the presentation. Certainly, more complex calculation are best performed in plain Javascript or on the server-side, but there are occasions when template code can be useful. Examples include:

  • Loops: A collection is passed in to the template. The template outputs the entire collection by looping over the collection. It's much better for the template to perform the looping, rather than the calling Javascript, because there is usually some HTML before and after the loop. If the Javascript was to output that HTML, there would be too much coupling between the Javascript and the template.
  • Conditionals: if-then conditions and switch statements are sometimes better performed by the template too. However, if the body of each branch is long, you might prefer to include a different template for each.

How to prepare the template's context?

In the case of Ajax Pages, you're allowed to pass in a context variable at rendering time. That's usually a good thing, as it provides a good alternative to the template using global variables. The most obvious thing to do is pass some existing objects to the template, but sometimes the calling code can prepare some extra information too. The aim is to perform as much processing in the Javascript code, so as to avoid any complex logic being performed within the template. For example, sometimes the template contains a simple if-then condition like this:

  <% if (context.credits ==  0) { %>
    You need more credits!
  <% } else { %>
    You have <%=context.credits%> credits!
  <% } %>

The logic isn't especially complex, but scaling up with this approach can be problematic. As an alternative, let the Javascript do some processing:

 var creditsMessage = credits ?
   "You need more credits!" : "You have " + credits + " credits!";

And the template then gives you a better idea of the outputted HTML:

  <%= context.creditsMessage %>


Real-World Examples

Ajax Pages Framework

Gustavo Ribeiro Amigo's Ajax Pages is an open-source templating framework. Basic usage is illustrated in the Solution above, and it's also included in the Refactoring Illustration below. Also, there's a basic blog demo on the project homepage.

Authenteo

Authenteo is an integrated JavaScript framework and content management system. Authenteo uses browser-side templating to dynamically generate HTML from the client accessible data domain model. The Authenteo templating engine allows you to create templates that generate HTML from the persisted objects of the domain model. The following is an example of a template:

<h2 logic="text" field="content.#name"></h2>
<div class="contents" logic="display" field="content.#body"></div>
<div logic="each" field="content.#items" class="listItem"> <!-- iterate through the items -->
  <a logic="hyperlink">
    <span logic="text" field="content.#name"></span>
  </a>
  <div logic="display" field="content.#description"></div>
</div>

The logic attribute defines the action, and the field attribute defines what value to grab. The # symbol denotes persisted fields should be accessed from the objects.

Distal

Distal is a JavaScript framework that implements Zope's TAL (Template Attribute Language) specification. Mark your HTML with TAL attributes and execute the Distal function with a JSON object as the parameter.

<div data-qtext="object.property"></div>

Call from within JavaScript:

distal(document.body, {object: {property: "Hello World"}});

Javascript Templates Framework

JavaScript Templates (JST) is an open-source templating framework from TrimPath. JST offers a richer set of functionality at this time, including:

  • Expression modifiers. The "capitalize" modifier, for instance, occurs in expressions like ${name|capitalize}.
  • A special syntax for loops and conditions.
  • Macros.

These features may be useful if you're relying heavily on templating, but there's also an argument that Javascript alone is sufficient, so there's no need to add the burden of learning a second set of similar syntax.

Here's how a JST template looks:

 {for p in products}
    <tr>
       <td>${p.name|capitalize}</td><td>${p.desc}</td>
       <td>$${p.price}</td>
       <td>${p.quantity} : ${p.alert|default:""|capitalize}</td>
    </tr>
 {/for}

With the string in a DOM element on the web page, you can apply the template with a one-liner:

 element.innerHTML = TrimPath.processDOMTemplate("templateElement", data);


JBST Controls via JsonFx

JsonFx.NET has an open-source implementation for a browser-side templating framework. It implements the JsonML+Browser-Side Templates (JSBT) pattern which has syntax similar to ASP/JSP but uses JavaScript as the templating language. At build-time, the templates are compiled to pure JavaScript. This allows them to be compacted and lazy loaded by web pages.

A complete example written completely with these JBST controls is available at: http://starterkit.jsonfx.net/

Jemplate

http://search.cpan.org/dist/Jemplate/

Allows you to use Perl's Template Toolkit syntax in javascript.


    var data = Ajax.get('url/data.json');
    var elem = document.getElementById('some-div');
    elem.innerHTML = Jemplate.process('my-template.html', data);

prototype.js

The ever-popular "prototype.js" framework now contains some templating capabilities: http://www.prototypejs.org/api/template


PURE Unobtrusive Rendering Engine

http://beebole.com/pure/

JavaScript Template Engine that keeps the HTML completely clean of all templating tags.

It supports jQuery, Prototype, DOMAssistant, MooTools and Sizzle.

HTML

  <div id="hello">
    Hello <span class="who">World</span>
  </div>

JavaScript

  $('#hello').autoRender({ "who": "Mary" })


QueryTemplates

http://code.google.com/p/querytemplates/

QueryTemplates - DOM and CSS oriented template engine. It completely separates markup and data.

QueryTemplates is available in 2 versions:

  • JavaScript based light version, available as jQuery plugin.
  • PHP based full version with support for generating JS and PHP templates, which are executed later, without the library itself.

JavaScript client-side example

$('body > ul > li')
  .valuesToLoop(data, function(row) {
      this.valuesToSelector(row.User, 'span.%k')
          .find('> ul > li')
              .valuesToLoop(row.Tags, function(tag) {
                  this.valuesToSelector(tag);
              })
      ;
  });

PHP Server-side example

$template = template('output', 'js')->
  parse('input.html')->
    find('ul > li')->
      varsToLoop('data', 'row')->
      varPrint('row')->
    end()->
  save('document.write')
;
header("Content-Type: application/x-javascript");
print 'var data = '.QueryTemplates::toJSON($data).";\n";
print(file_get_contents($template));

django (a Python framework)

It's important to bear in mind that you are not limited to JavaScript in your search for good ideas! Django, an open-source web framework implemented in the Python programming language (http://www.djangoproject.com), implements some very innovative templating ideas, which can be easily adapted to the world of JavaScript. (And it may well have already been done.)

For example, in Django, a template is effectively compiled, into an internal data-structure, which is then traversed to generate the output. It is, in other words, a process that is considerably more sophisticated and flexible than simple pattern-matching.

Django also provides the concept of a "template tag," which causes Python code to be executed but which does not, itself, consist of Python code. This allows the template to specify behaviors that can only be accomplished by means of executing a programming-language subroutine, without embedding "live" source-code into the template (as the AJP-based illustrations in this article do).

.. and more!

In short... the "real-world examples" listed here are only a representative sample of the myriad possibilities that exist, both in the world of JavaScript and otherwise. Client-side templating is such a generally-useful concept that a great many implementations of it have been built, in languages of all kinds.

These implementations are, categorically speaking, generally very sophisticated, yet they can be obtained as components which you can simply "drop in" to your projects.

Before embarking on your project, therefore, spend some time researching the various possibilities that are available to you "today." The illustrations in this article, or in any article, are necessarily just that: illustrations.

Refactoring Illustration

Templating Drilldown Demo

Initial Version

In the Drilldown Demo, the Drilldown menu itself is a bunch of HTML generated within Javascript. The script picks up an XML file containing a specification for the current level, and traversed it with standard Javascript and XML access. See Drilldown for details, but as a quick summary, the XML file looks like:

  <category name="Overviews" parent="All Categories">
    <items>
      <link>
        <url>http://en.wikipedia.org/wiki/AJAX</url>
        <name>Wikipedia Article</name>
      </link>
      <link>
        <url>http://www.adaptivepath.com/publications/essays/archives/000385.php</url>
        <name>First Ajax</name>
    </link>
    <category name="Podcast Overviews" parent="Overviews" />
  </items>
  </category>

And the manual HTML generation looks like this:

  function onDrilldownResponse(xml) {
 
    var category = xml.getElementsByTagName("category")[0];
    var html="";
 
    var categoryName = category.getAttribute("name");
    html+="<div id='categoryName'>" + categoryName + "</div>";
    ....
    *** Much more appending to html ***
    ...
    $("drilldown").innerHTML = html;

  }

Refactored To Render from a Template

For all the reasons described earlier, the HTML generation here is a messy approach. The present example refactors the application to use a template for the drilldown menu. Instead of the lengthy HTML generation in onDrilldownResponse(), the method becomes a simple application of an AjaxPages template.

 function onDrilldownResponse(xml) {

   var ajp = new AjaxPages();
   ajp.load("category.ajp");
   var processor = ajp.getProcessor();
   $("drilldown").innerHTML = processor( {xml: xml} );

 }

So we're passing the entire xml string into the template, and the template's converting it to HTML. Let's see how that template ("category.ajp") looks. First, it performs a little pre-processing on the XML string.

  <%
    var category = context.xml.getElementsByTagName("category")[0];
    var categoryName = category.getAttribute("name");
    var parent = category.getAttribute("parent");
    var items = category.getElementsByTagName("items")[0].childNodes;
  %>

Then, it outputs the HTML. Note that looping and conditions are implemented with regular Javascript, a reasonable time to include Javascript in a template.

  <div id='categoryName'><%=categoryName%></div>

  <%
    if (parent && parent.length > 0) {
  %>
      <div id='parent' onclick="retrieveCategory('<%=parent%>')">Back to <br/>
      <%=parent%></div>
  <% } %>

  <%
    for (i=0; i<items.length; i++) {
      var item = items[i];

      if (item.nodeName=="link") {
        var name = item.getElementsByTagName("name")[0].firstChild.nodeValue;
        var url = item.getElementsByTagName("url")[0].firstChild.nodeValue;
  %>
        <div class="link"><a href="<%=url%>"><%= name %></a></div>
  <%
      } else if (item.nodeName=="category") {
        var name = item.getAttribute("name");
  %>
        <div class='category'
             onclick="retrieveCategory('<%=name%>')"><%=name%></div>
  <%
      }
    }
  %>

We now have exactly the same external behaviour as before, but the templating approach has helped separate presentation from logic.

Refactored to Improve Template Context

In the refactored version, the context consisted of only one thing: the entire XML string. As mentioned in the Decisions above, it's sometimes worthwhile doing preparing work before passing the context over to the template. In this case, the template begins by extracting out a few convenience variables from the XML. That's arguably a good approach, because it means the XML format is coupled only to the template, and not the Javascript. However, there's also an argument that the Javascript should simplify the template's work by passing in a richer context. This further refactoring explores that avenue.

The change is quite small. The xml callback function now passes in a more detailed context:

  function onDrilldownResponse(xml) {
    var ajp = new AjaxPages();
    ajp.load("category.ajp");
    var processor = ajp.getProcessor();
    var category = xml.getElementsByTagName("category")[0];
    $("drilldown").innerHTML = processor({
      categoryName: category.getAttribute("name"),
      parent: category.getAttribute("parent"),
      items: category.getElementsByTagName("items")[0].childNodes
    });
  }

The template no longer includes the first few lines of creating convenience variables. References to those variables have been changed throughout to refer to context:

  <%
    if (context.parent && context.parent.length > 0) {
  %>
      <div id='parent' onclick="retrieveCategory('<%=context.parent%>')">Back to
        <br/>
      <%=context.parent%></div>
  ...


Alternatives (and Issues)

Browser-Side XSLT

In many cases, the browser receives an XML response. Where the browser is converting XML to HTML, Browser-Side XSLT is a very direct alternative to this Browser-Side Templating. Templating simplifies presentation, but still requires parsing of the XML, which can be cumbersome. XSLT simplifies the parsing as well, being designed specifically for the purpose of transforming XML.

Browser-Side JSONT

Analogous to XML/XSLT transformation, JSONT, a Json Frameworks, transforms data in JavaScript Object Notation (JSON) into HTML using a set of rules. The rules themselves are written in JSON.

The Problem of Embedded Code in Templates

You may have noticed that, throughout the illustrations shown above, a considerable amount of JavaScript source code is embedded, verbatim, inside the templates. The looping, and other similar behaviors, is literally being accomplished by executable code that is contained within the template.

While this technique is inarguably powerful, it also creates a functional dependency between the code in the main JavaScript application and the code that is scattered throughout the (potentially hundreds of...) individual templates. It could easily be argued that this does not maintain "separation of presentation from logic." It could certainly become a maintenance issue as your application continues its lifetime of service. (On the other hand, it could work splendidly and present no practical problems at all!)

One solution to this is the twoBirds library, an on-demand-everything loader that features 100% separation between code and design ( HTML, CSS, JS are loaded separately by coding design) twoBirds prototype. twoBirds is not a template engine, templating is the JS programming concept here.

Many templating systems exist, for JavaScript and for other languages, and they all have different ways to implement the features and behaviors that designers have found useful. Every one of these implementations constitutes some combination of trade-offs. Consider your options prudently.

The "Weight" That You Place on the Client-Side

A full-featured templating system can place a considerable burden upon the browser, and it may expose limitations or implementation-differences from one browser type to another, to which a different approach might not be susceptible. It is important to carefully consider the range of browser-types that you must support, and the potential age of those browsers. The critical importance of testing also cannot be over-emphasized.


Related Patterns

Semantic Response

The importance of templating mostly arises from the need to deal with data structures passed back from Semantic Responses.

XML Message

Templating is well-suited to transforming an XML Message into HTML.

JSON Message

Templating is well-suited to transforming an object from a JSON Message into HTML.


Visual Metaphor

Think of a physical template - a document with most content already present, with a few blanks to populate with current values.


Want to Know More?