BuildMobile: Mobile Web Apps: Templating

In the sixth excerpt from the book “Build Mobile Websites and Apps for Smart Devices” by Earle Castledine, Myles Eftos and Max Wheeler we learn about templating. BuildMobile is publishing the chapter “Mobile Web Apps” from the book, this section is called “Templating”.

6. Templating

Pulling in an entire dollop of ready-to-go HTML via Ajax makes it nice and easy to stick in your page, but typically this isn’t the data format you’ll receive from a web service or API. This means it’s our responsibility to turn data into markup. Even if you’re in control of the back end, it still makes sense to transmit your site data in XML or JSON rather than HTML, since those files will usually be much smaller, and require less of your mobile users’ precious bandwidth.

So, how will this work? We start by receiving a list of data from the server. For each item in the list, we want to create an HTML fragment (such as a list item) and inject some values from the data. Finally, we want to add each fragment into the correct place in the page. There are a few common ways to approach this situation:

  • build the HTML fragments ourselves, in JavaScript
  • duplicate a “template” DOM element and change the contents of the relevant tags
  • use a templating engine

We’ll quickly visit each approach and see what works best in which contexts. We’ll be assuming our data source is in the JSON format, and looks a little like this:

Example 4.58. data/spots.json (excerpt)

[{
  "id": 4,
  "name": "Planet Bollywood",
  "distance": "400m",
  "sightings": 10
}, {
  "id": 7,
  "name": "Soft Rock Café",
  "distance": "1.1Km",
  "sightings": 3
}]

It’s a simple array, with each element consisting of an object containing details about locations. This is a very common (albeit simplified) format for the data that we’re likely to receive. To fetch it into our application, we can use jQuery’s getJSON() method:

Example 4.59. javascripts/ch4/15-templating.js (excerpt)

$.getJSON("../data/spots.json", function(data){
  // Got JSON, now template it!
});

With some data in our pocket, it’s time to show it to the world. The first of our three approaches is to loop over the data array, building up HTML strings that can then be added into the DOM:

Example 4.60. javascripts/ch4/15-templating.js (excerpt)

$.getJSON("../data/spots.js", function(data){
  // Got JSON, now template it!
  var html = "";
  for(var i = 0; i  data.length; i++) {
    html += "lia href='#'";
    html += "h2" + data[i].name + "/h2";
    html += "/a/li";
  }
  $("#spots-list").append(html);
});

This is a very old-school approach, and while it can work for very simple examples, it tends to scale poorly: it’s error-prone, difficult to maintain, and degenerates fairly quickly into a huge mess of mashed-together HTML and data.

The separation of data and presentation is important, and this is especially true for web applications. Using the previous method, if a designer wanted to make changes to the HTML, they’d either have to know some JavaScript (and potentially risk breaking something), or come and bother you about it. We would prefer to avoid being bothered, so a better solution is to include the HTML where it belongs—in the HTML page:

Example 4.61. ch4/16-templating-2.html (excerpt)

div id="tmpl-simple" style="display:none;"
  li
    a href="spot.html" data-load="spot"
      h2/h2
      span class="relative-distance"/span
      span class="sightings"/span
    /a
  /li
/div

We’ve constructed a generic fragment that’s empty of any data. When we receive data from the server, we can clone this template and fill it with our data. It can be as complex as it needs to be, as long as there are some hooks for us to inject our data into. Of course, you don’t want an empty row in the list shown to the user—so the template needs to be hidden. In the above example, this is done using display: none;.

To make use of the fragment, we’ll clone it with jQuery’s clone() method, and then inject all the pieces of data into their correct elements using the text() method:

Example 4.62. javascripts/ch4/16-templating-2.js (excerpt)

$.getJSON("../data/spots.json", function(data){
  // Got JSON, now template it!
  $.each(data, function(){
    var newItem = $("#tmpl-simple").clone();
    // Now fill in the fields with the data
    newItem.find("h2").text(this.name);
    newItem.find(".relative-distance").text(this.distance);
    newItem.find(".sightings").text(this.sightings);
    // And add the new list item to the page
    newItem.children().appendTo("#spots-list")
  });
  transition("#spots", "show");
});

This solution works well, leaving all the HTML in one file and all the JavaScript in another. It’s much nicer than our first approach, and is suitable for small static templates. But it’s less ideal if the HTML is continually changing, and for large pages it requires us to write a lot of generic JavaScript to replace all the field values.

This is the kind of mind-numbing code that we want to automate away. Perhaps we could add some tokens in the HTML that could be automatically replaced from a given data object? That’s quite a good idea, and it turns out plenty of developers have had it before: it’s called a templating engine. Choosing a templating engine is like choosing a text editor: there are a lot out there, they have a many different features, most of them are fine, and ultimately it’s up to you which one you (or your company) likes the best.

One “big one” that you’ll see mentioned time and time again is Mustache. It’s available for many programming languages, and the template format is the same for all of them—which makes it worth becoming familiar with (though it also means that we’re unable to use JavaScript’s dot notation because it clashes with some other languages).

However, given that we’re already using jQuery, we’re in luck. In 2008, John Resig (the creator of jQuery) released a novel and extremely small templating engine made up of around 20 lines of JavaScript. It has since been expanded into a full jQuery library that is considered the officially sanctioned jQuery templating engine: the code is available from the jQuery repository on GitHub and the documentation is located on the jQuery plugin site.

To use the library, download the archive from GitHub and extract the minimized file. It will be called jquery.tmpl.min.js, and is only about 8KB in size. Copy this into your project to load it up:

script src="jquery.tmpl.min.js" type="text/javascript"/script

6.1. Twitter Integration with Templating

Having brought out the big guns—the jQuery templating engine—we need something a bit more juicy to use it on. The client has been toying with the idea of integrating some Twitter data into the app. Specifically, they noticed that Twitter does a good job of celebrity stalking too—and they want to harness that stalking power in their app.

The plan is to use a public search on the query term “celeb spotting,” and display any tweets that match. Generally, you can’t make cross-domain Ajax requests (it’s a security issue—in fact, the same security issue that prevents you from placing Ajax requests to file:// URLs)—but Twitter provides data in JSONP format. JSONP is a common trick to grab data across domains by loading it inside a script tag. For this to work, we need to append the string "callback=?" to the URL request.

We’ve had a look at the Twitter API documentation, and found the appropriate URL to conduct a search: http://search.twitter.com/search.format?q=query. All we need to do is call getJSON() with that URL and our search string:

Example 4.63. javascripts/ch4/17-twitter-templating.js (excerpt)

var twitQuery = "celeb+spotting",
    twitUrl = "http://search.twitter.com/search.json?q=";
$.getJSON(twitUrl + twitQuery + "callback=?", function(data){
  // Show some tweets
});

Now we have some data from Twitter! The tweets are stored in the results property of the data object as an array, so we can use them directly in our template system.

Templates used in templating engines are defined in the same manner as the simple template we put together earlier: as elements inside our HTML file. The jQuery templating engine uses a clever trick to prevent the template from becoming a regular part of the DOM: it hides inside a script tag with type="text/x-jquery-tmpl". Browsers don’t know how to handle this type of “script,” so they don’t try to execute it, but we can still extract the content and use it as a template:

Example 4.64. ch4/17-twitter-templating.html (excerpt)

script id="tmpl-tweet" type="text/x-jquery-tmpl"
  li
    a class="avatar" href="#"img src="${profile_image_url}" alt="${from_user}"/a
    a href="http://twitter.com/${from_user}"h2${from_user}/h2/a
    span class="details"
      ${text}
    /span
  /li
/script

Template Types

Even if you’re not using the jQuery templating engine, you can use the script trick with your own templates. You should use a different option to x-jquery-tmpl though; you can make up your own type if you want, but you’ll often see the text/html used.

You’ll notice that inside the HTML there are some odd-looking bits. These are are our tokens that will be replaced with data. The strings inside the curly braces aren’t made up: they are the names of the values that are returned to us from Twitter. To find out exactly what data is returned by a given API call, you can either read the documentation, or simply log the data object to the console using console.log(data);.

All that’s left to do now is to call the templating function. Just select the template item by id (we’ve called ours tmpl-tweet), and call the tmpl() method, passing the data.results array we retrieved via Ajax. The engine will see that our array has multiple items; for each item it will generate a clone of the template and replace all the tokens with the corresponding values from the data array. The result is a jQuery object containing the constructed DOM node, which we can inject into the page as we’d normally do:

Example 4.65. javascripts/ch4/17-twitter-templating.js (excerpt)

$.getJSON(twitUrl + twitQuery + "callback=?", function(data){
  $("#tmpl-tweet")
    .tmpl(data.results)
    .appendTo("#spots-list");
    transition("#spots", "show");
});

No need to do any looping or manual value insertion. The combination of data-rich APIs and simple templating engines gives you a lot of power as a developer, easily enabling you to enrich your applications with information from a variety of sources. A sample result from our Twitter search is shown in Figure 4.5, “Pulling in celebrity spottings from Twitter”.

Figure 4.5. Pulling in celebrity spottings from Twitter

fig_4_twitter

The jQuery template engine also includes tags for conditional evaluation like {{if}} and {{else}}, so you can show different parts of your template according to the situation. Check out the documentation for the full breakdown of available functionality.

Build Mobile Book

You can purchase the book “Build Mobile Websites and Apps for Smart Devices” from Sitepoint. Read the whole of Chapter 4. Mobile Web Apps, exclusively here at BuildMobile, for free, in the following sections.