Monday, August 23, 2010

Client-side Data Binding with jQuery Templates

Client-side data binding via templates is nothing new.  But as with all things jQuery, jQuery Templates makes it easier - more flexibility and options with less code.  I do believe that this jQuery plug-in is Microsoft's first contribution to jQuery, and it's a yummy one.  Here's a small example that shows how to bind user data to a grid:

First, define the grid:
<table id="userTable">
    <thead>
        <tr>
            <th>First Name</th>
            <th>Last Name</th>
            <th>Email</th>
        </tr>
    </thead>
    <tbody></tbody>
</table>

Then define the template for each grid row:
<script id="tmpl_userList" type="text/html">
    <tr class="${alternate(this.data, this.dataSource)}">
        <td>${FirstName}</td>
        <td>${LastName}</td>
        <td>${Email}</td>
    </tr>
</script>
Notice that the class attribute's value is set via javascript function that takes two arguments: the data item (for this particular grid row), and the complete data source, which is a custom parameter being passed into the template (more on that later).

Alright, we are now ready to retrieve our data and bind.

Let's provide some data from the server:
[HttpGet]
public JsonResult GetUsers()
{
    JsonResult result = new JsonResult { JsonRequestBehavior = JsonRequestBehavior.AllowGet };

    List<User> users = new List<User>();

    users.Add(new User
    {
        ID = 1,
        FirstName = "Jennifer",
        LastName = "Jones",
        Email = "test1@test.com"
    });

    users.Add(new User
    {
        ID = 2,
        FirstName = "Jason",
        LastName = "Johnson",
        Email = "test2@test.com"
    });

    users.Add(new User
    {
        ID = 3,
        FirstName = "Jerry",
        LastName = "Jones",
        Email = "test3@test.com"
    });

    result.Data = new JsonResultData { Value = users };

    return result;
}

Now let's call GetUsers() via an Ajax call and bind the returned data to our grid/table:
$.ajax({
    url: 'Home/GetUsers',
    success: function (response) {
        if (response.Success) {
            var data = response.Value;

            // Use template called tmpl_userList 
            // dataSource is a custom parameter we pass into the template.
            $.tmpl('#tmpl_userList', data, { dataSource: data })
                // Inject data into table userGrid
                .appendTo($('#userGrid')
                // Define event handlers for each row
                .click(function () {
                    var item = $.tmplItem(this);
                    alert(item.data.FirstName + ' ' + item.data.LastName + ' says, "Hi!"');
                })
                // Toggle row color
                .hover(    
                    function () {
                        $(this).addClass('userRowSelected');
                    },
                    function () {
                        $(this).removeClass('userRowSelected');
                    }
                );


        }
    }
});

Background colors used for alternating and selected grid rows:
.userRowAlt
{
    background-color: #F7F8E0;
}

.userRowSelected
{
    background-color: #F2F2F2;
}

And our resulting grid:
grid data bound on the client side via jQuery template

If we examine the rendered HTML, we'll find that the template's markup basically got injected into the <tbody> content:

<table id="Table1">
  <thead>
    <tr>
      <th>First Name</th>
      <th>Last Name</th>
      <th>Email</th>
    </tr>
  </thead>
  <tbody>
    <tr class="userRow">
      <td>Jennifer</td>
      <td>Jones</td>
      <td>test1@test.com</td>
    </tr>
    <tr class="userRow userRowAlt">
      <td>Jason</td>
      <td>Johnson</td>
      <td>test2@test.com</td>
    </tr>
    <tr class="userRow">
      <td>Jerry</td>
      <td>Jones</td>
      <td>test3@test.com</td>
    </tr>
  </tbody>
</table>

And that's it really. Simple, clean, fun!

You can download the complete, fully functional solution here. The solution code is organized slightly differently, with most of the client-side script located inside the .js include. This way you can also see how the HTML markup, templates and script implementation (including data binding) can be cleanly separated and organized.

UPDATE - 10/06/2010:
This jQuery Templates is now an official jQuery plug-in.

2 comments:

  1. This is really very good.If there are pagination and dynamic data bindings also included then it will be extremely helpful

    ReplyDelete