Channels ▼
RSS

JVM Languages

Integrating jQuery Client-Side Data Templates with WCF


Dan Wahlin (Microsoft Most Valuable Professional for ASP.NET and XML Web Services) is the founder of The Wahlin Group (www.TheWahlinGroup.com) which provides .NET, SharePoint, and Silverlight consulting and training services. Dan blogs at http://weblogs.asp.net/dwahlin.


In my article Minimize Code by Using jQuery and Data Templates, I presented a JavaScript data binding template solution that I've been using that makes it easy to bind JSON data to a client-side template without having to write a lot of JavaScript code. In this article, I demonstrate the fundamentals of using the client-side templates and binding JSON data that's retrieved from a WCF service. As a review (in case you didn't read the previous article), the template solution I've been using recently on a client project is based on some code written by John Resig (creator of jQuery) which is extremely compact. Here's a modified version of his original code that I wrapped with a jQuery extender:


$.fn.parseTemplate = function(data)
{
    var str = (this).html();
    var _tmplCache = {}
    var err = "";
    try
    {
        var func = _tmplCache[str];
        if (!func)
        {
            var strFunc =
            "var p=[],print=function(){p.push.apply(p,arguments);};" +
                        "with(obj){p.push('" +
            str.replace(/[\r\t\n]/g, " ")
               .replace(/'(?=[^#]*#>)/g, "\t")
               .split("'").join("\\'")
               .split("\t").join("'")
               .replace(/<#=(.+?)#>/g, "',$1,'")
               .split("<#").join("');")
               .split("#>").join("p.push('")
               + "');}return p.join('');";

            //alert(strFunc);
            func = new Function("obj", strFunc);
            _tmplCache[str] = func;
        }
        return func(data);
    } catch (e) { err = e.message; }
    return "< # ERROR: " + err.toString() + " # >";
}

The parseTemplate method can be applied against a client-side template like the one below. Notice that the template is wrapped in a script block with the type set to text/html so that it isn't rendered by the browser. JSON properties are written out by using the <#= … #> syntax and the template engine has full support for embedded JavaScript code.


<script id="MyTemplate" type="text/html">
    <table style="width:400px;">
        <thead>
            <tr>
                <th>First Name</th>
                <th>Last Name</th>
                <th>Address</th>
            </tr>
        </thead>
        <tbody>
        <#
            for(var i=0; i < d.length; i++)     
            {      
               var cust = d[i]; 
        #>
                <tr>
                   <td id="CustomerRow_<#= i.toString() #>">
                        <#= cust.FirstName #> 
                   </td>
                   <td>
                        <#= cust.LastName #>
                   </td>
                   <td>
                      <#= cust.Address.Street #>
                      <br />
                      <#= cust.Address.City #>, <#= cust.Address.State #>
                        <#= cust.Address.Zip #>
                   </td>
                </tr>
        <# 
            }
        #>
        </tbody>
    </table>
    <br />
    <#= d.length #> records shown
</script>

This template outputs a simple table like Figure 1. Sure, I could have generated the table using DOM manipulation techniques, but being able to tweak a data template is much easier and productive in my opinion.

Figure 1

To use the template you'll need to have some JSON data available. Here's an example of creating JSON by hand and binding it to the template using the parseTemplate method shown earlier. The data returned from the template data binding operation is passed to the html method of the target div which displays the data in the browser. Note: I'm defining the d property in the JSON object since WCF uses that name by default when it returns serialized JSON data.


var json =
        {
            "d":
            [
               { "FirstName": "John", "LastName": "Doe", 
                 "Address":
                  { "Street": "1234 Anywhere St.", "City": "Phoenix", 
                    "State": "AZ", "Zip": 85044 }
               },
               { "FirstName": "Jane", "LastName": "Doe",
                   "Address":
                  { "Street": "435 Main St.", "City": "Tempe", 
                    "State": "AZ", "Zip": 85245 }
               },
               { "FirstName": "Johnny", "LastName": "Doe", 
                 "Address":
                  { "Street": "643 Chandler Blvd", "City": "Chandler", 
                    "State": "AZ", "Zip": 85248 }
              },
               { "FirstName": "Dave", "LastName": "Doe",
                 "Address":
                  { "Street": "18765 Cloud St.", "City": "Mesa", 
                    "State": "AZ", "Zip": 85669 }
               }
            ]
        };
var output = $('#MyTemplate').parseTemplate(json);
$('#MyTemplateOutput').html(output);

Of course, in the real-world you'll probably get the JSON data from some type of service (WCF, ASMX, REST, etc.). Here's a WCF service that returns a List of Customer objects and converts them to JSON. The service has the client script behavior enabled so that serialization from CLR objects to JSON objects occurs behind the scenes automatically.


[ServiceContract(Namespace = "http://www.thewahlingroup.com")]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class CustomerService
{
    [OperationContract]
    public List<Customer> GetCustomers()
    {
        return new List<Customer>
        {
            new Customer {FirstName="John",LastName="Doe", 
                          Address=
                           new Address{
                           Street="1234 Anywhere St.",
                           City="Phoenix",State="AZ", Zip=85044}},
            new Customer {FirstName="Jane",LastName="Doe", 
                          Address=
                           new Address{
                           Street="435 Main St.",
                           City="Tempe",State="AZ", Zip=85245}},
            new Customer {FirstName="Johnny",LastName="Doe", 
                          Address=
                          new Address{
                          Street="643 Chandler Blvd",
                          City="Chandler",State="AZ", Zip=85248}},
            new Customer {FirstName="Dave",LastName="Doe", 
                          Address=
                          new Address{
                           Street="18765 Cloud St.",
                           City="Mesa",State="AZ", Zip=85669}}
        };
    }

}

jQuery's ajax method can then be used to call the WCF service and retrieve the data (jQuery provides other methods such as getJSON that could be used too if desired):


$.ajax(
{
    type: "POST",
    url: "CustomerService.svc/GetCustomers",
    dataType: "json",
    data: {},
    contentType: "application/json; charset=utf-8",
    success: function(json)
    {
        var output = $('#MyTemplate').parseTemplate(json);
        $('#MyTemplateOutput').html(output);

        //Add hover capabilities
        $('tbody > tr').bind('mouseenter mouseleave', function()
        {
            $(this).toggleClass('hover');
        });
    }
});

This code defines the type of operation, service URL to call, any data passed to the service, the content type, and a success callback. Once the service call returns, the JSON data is bound to the template shown earlier by locating the area where the template should be rendered to (MyTemplateOutput in this example) and then calling parseTemplate. Hover capabilities are also added using jQuery's bind method to highlight rows as the user moves the mouse in and out of them.

You can see that the amount of custom Javascript that has to be written is kept to a minimum by combining jQuery with the client-side template which ultimately leads to easier maintenance down the road. This is just one of several different client-side template solutions out there. ASP.NET 4.0 will also include a custom client-side template solution as well once released. You can download the sample code here.


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.
 

Video