jQuery JavaScript Templates Tutorial: Nesting Templates

In my last post, I presented an intro to how to create a template using the new jQuery Template plugin being developed by the Microsoft Ajax Core team. In this tutorial, I’ll show you how to nest templates to have great control over your layout.

The nesting of a template within another template is a pretty valuable feature as it lets you create a modular structure for your layout. Instead of having to create one enormous template to cover every scenario, you can break the layout apart into individual templates and piece them together. Let’s start by defining some data:

[code language=”js”]
var clientData = [
{ name: "Rey Bango", age: 42, id: 1, phone: [ "954-600-1234", "954-355-5555" ] },
{ name: "Mark Goldberg", age: 51, id: 2, phone: ["954-600-1234", "954-355-5555"] },
{ name: "Jen Statford", age: "25", id: 3, phone: ["954-600-1234", "954-355-5555"] }
];
[/code]

What I’d like to do is to render the basic information like the name and age in one template and then render the phone numbers for each client in a different template.

Like I showed in my previous post, we first create a template for our layout:

[code language=”js”]
<script id="clientTemplate" type="text/html">
<p><a href="clients/${id}">${name} – Age: ${age}</a></p>
</script>
[/code]

This will display the name and age as a hyperlink included within paragraph tags. Next, we create a new template that will be used to render the phone numbers for each client”

[code language=”js”]
<script id="phoneTemplate" type="text/html">
<ul>{{each phone}}<li>${$value}</li>{{/each}}</ul>
</script>
[/code]

Lastly, we’re going to include the call to “phoneTemplate” in our main template using the “tmpl” tag. This tag is used by the plugin to identify templates and parse them accordingly. Here’s what the call would look like:

[code language=”js”]
{{tmpl($data) "#phoneTemplate"}}
[/code]

and we’re going to include it into the main template:

[code language=”js”]
<script id="clientTemplate" type="text/html">
<p><a href="clients/${id}">${name} – Age: ${age}</a></p>
{{tmpl($data) "#phoneTemplate"}}
</script>
[/code]

This will generate the following results:

There are a couple of key things to understand here. First, let’s look at the following:

[code language=”js”]
{{tmpl($data) "#phoneTemplate"}}
[/code]

The variable “$data” contains the data for the current record being parsed. We’re passing it to the nested template so that we can work with that record. Let’s move onto the nested template:

[code language=”js”]
<script id="phoneTemplate" type="text/html">
<ul>{{each phone}}<li>${$value}</li>{{/each}}</ul>
</script>
[/code]

Now that the current record has been passed to it, we can access the attribute name, in this case “phone”, and loop through each phone record using the ‘{{each}}‘ plugin template tag. Think of it as similar to jQuery’s $.each() method or a JavaScript “for” loop. The code will loop through each phone record creating a new list item for each one and then return to the main template to get the next main record.

Here’s the whole code for you to work with:

[code language=”html”]
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="robots" content="noindex" />
<title>Template Test</title>
<script src="http://code.jquery.com/jquery.min.js" type="text/javascript"></script>
<script src="jquery.tmpl.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function() {

var clientData = [
{ name: "Rey Bango", age: 42, id: 1, phone: [ "954-600-1234", "954-355-5555" ] },
{ name: "Mark Goldberg", age: 51, id: 2, phone: ["617-777-1234", "617-222-3333"] },
{ name: "Jen Statford", age: "25", id: 3, phone: ["608-555-5647", "608-645-8855"] }
];

$("#clientTemplate").tmpl(clientData).appendTo("div");

});
</script>

<script id="clientTemplate" type="text/html">
<p><a href="clients/${id}">${name} – Age: ${age}</a></p>
{{tmpl($data) "#phoneTemplate"}}
</script>

<script id="phoneTemplate" type="text/html">
<ul>{{each phone}}<li>${$value}</li>{{/each}}</ul>
</script>

</head>

<body>

<div></div>

</body>
</html>
[/code]

Rey Bango

28 Comments

  1. Rey,

    I’m fascinated by what is happening here between jquery and Microsoft, but my off-the-cuff reaction is: Does anyone ever need to bind from client data? Usually, data is on a db server. How about a full-service example, starting from a db server, then getting to client and rendering? Then, enabling CRUD functionality?

    Cheers,
    Bill

  2. @Bill,

    The data can be retreived using jQuery.ajax method, so you can use the received data object instead of the hardcoded example.

    jQuery(function(){
    jQuery.ajax({
    url: ‘/someJSONService’,
    success: function(data){
    $(‘#clientTemplate’).tmpl(data).appendTo(‘div’);
    }
    });
    });

    You can also send data with ajax and jQuery has some good documentation on how to achieve this. How you set up CRUD services however is kinda outside of scope of this article/jQuery plugin. I suggest setting up RESTfull services and using jQuery.ajax to post requests, there are many articles on the net on this very topic, just do a search ;)

    • Thanks for answering that Ben. That’s actually the example I showed in my presentation yesterday. Great minds! :D

      • Thanks so much for the reply Rey and Ben! When I get unburied from work, I will take a much closer look at that example. Best wishes.

    • Hmm I’m getting notified of new comments. I wonder if it’s isolated to you or if no one is getting notifications.

  3. thanks for the example and very timely indeed. Your original post had me thinking about this and I happened to come across this post :-)

    I have been playing with 3 levels of nesting (and kinda got it working) by nesting {{each}}. Is there a nicer way of doing this? I guess what I am trying to say is can we not add a {{tmpl($data) “#someTemplate”}} for each level of nesting?

    Thanks

    J

  4. Ray, I’m loving these templates, they are going to make my life so much easier. Do you know if the creators are talking about any kind of form elements to add to the templates? For instance, if I wanted to add a row to a table, and one of the cells of the table was a select, it would require some fun coding right now, to create the select and then select the item you want selected by default.

    • Great work Ray!
      @Anton Visser: Your suggestion is exactly what I’m trying to do, did you start working on this template? I couldn’t figure out how to choose the default option (selected)

  5. You can use multiple sets of data (multiple JSON objects) as sources for the nested templates.

    For example, I needed to for each user, display a drop down that allows the choice of several dynamic options. I chose to make them a separate JSON object, for sake of bytes transferred to the server.

    So…

    var clientData = [
    { name: “Rey Bango”, age: 42, id: 1, phone: [ “954-600-1234”, “954-355-5555” ] },
    { name: “Mark Goldberg”, age: 51, id: 2, phone: [“617-777-1234”, “617-222-3333”] },
    { name: “Jen Statford”, age: “25”, id: 3, phone: [“608-555-5647”, “608-645-8855”] }
    ];

    var dropDownOptions = [
    { text: “Text 1”, value: 1 },
    { text: “Text 2”, value: 2 },
    { text: “Text 3”, value: 3 }
    ];

    $(“#clientTemplate”).tmpl(clientData).appendTo(“div”);

    ——————————-

    Looks normal, right? Then, in the template, instead of referencing the data object as {{tmpl($data) “#ddTemplate”}}, you reference it as {{tmpl(dropDownOptions) “#ddTemplate”}}

    ——————————-

    So, for example, I needed to display a drop down list with dynamic options in it…

    <select>
    {{tmpl(dropDownOptions) “#ddTemplate”}}
    </select>

    ——————————-

    and my template definition is:

    <option value=’${value}>${text}</option>

    Thanks for the article! Very helpful

  6. thanks. this helped me a lot! I followed your instructions modified for my project thinking “ugh this is never going to work” but got it on the first try. cheers!

  7. Hi,

    I realize this has been posted a while ago, but I’ll try my luck at asking a question.

    I don’t get the “clients/${1}” part in the href. What purpose does it serve?

    Thanks in advance! :)

    David.

  8. Hey great post.
    I have a question about going deeper into each json object.
    Take:
    [
    {“Name”:”Home”,”NiceUrl”:”/home/”,”Children”:null},
    {“Name”:”MX-8″,”NiceUrl”:”/mx-8/”,”Children”:null,{“Name”:”Quiz”,”NiceUrl”:”/quiz/”,”Children”:
    [{“Name”:”Thank you”,”NiceUrl”:”/quiz/thank-you/”,”Children”:
    [{“Name”:”Can’t get here”,”NiceUrl”:”/URL/”,”Children”:null}]}]}}
    ]

    Using your example above i can easily get to “Quiz” and its child “Thankyou” but is there a way to recursively call a second template?

    I have tried setting the type of the second template to “text/x-jquery-tmpl” and calling a 3rd template but the data being passed is

  9. Wonderful post.

    I just have a question….
    I need to call a span, div or td “whatever” with their id or class to add a function to them from another js file.

    For example “related to your code above”:

    – If the code of the template is like that,

    {{each phone}}${$value}{{/each}}

    I need now to call the div by it’s id “example” in another js file with a basic jquery code like the following:

    $(document).ready(function () {
    $(“#example”).hide();
    });

    But I find that nothing change, and I don’t know why ????????????!!!!!!!!!

    ————–
    Thanks.

  10. Sorry there’s something going wrong.

    I meant the code of the template looks like the following:

    {{each phone}}${$value}{{/each}}

  11. mmm you closed typing tags in your comment forms.

    Anyway I meant looks like the following:

    (script id=”phoneTemplate” type=”text/html”)
    (ul){{each phone}}(li)${$value}(/li){{/each}} (/ul)
    (/script)

  12. (script id=”phoneTemplate” type=”text/html”)
    (ul id=”example”){{each phone}}(li)${$value}(/li){{/each}} (/ul)
    (/script)

  13. Hi Ray,
    I know this is an older post, but I stumbled upon it just today when searching for nested template information.

    The problem is that the information I need to show (in your example: the field w/ phonenumbers) in my case is a collection of objects itself from which I need to show only one or two fields.

    for example
    phone: [{phone-home: “954-600-1234”, phone-work: “954-355-5555″, phone-mobile:” …”}, {…} ]

    How do I get to the value of ‘phone-home’?

    I tried notation like {{each phone}}${$value.phone-home}{{/each}}

    and

    {{each phone}}${$value[“phone-home”]}{{/each}}

    and various others. But to no avail.

    Any help is greatly appreciated.

    regards,
    Peter.

Comments are closed.