Client-side Data Binding in ASP.NET AJAX 4.0

by Fritz Onion
ASP.NET Ajax 4.0 introduces a brand new client templating and data binding model that is intuitive to use, powerful, flexible, and XHTML-compliant. This article covers these features including the DataView, client templates, and declarative object creation.

The 4.0 release of ASP.NET AJAX will include a significant number of new features targeted at client-side programming. Earlier releases of ASP.NET AJAX included client-side programming features like web service proxies, global helper functions (like $get and $create), client library additions (like Sys.StringBuilder), and a complete set of extensions to add classes, namespaces, interfaces, and inheritance to the JavaScript language. Most of these features, however, were targeted at supporting the developer in building client-side features by hand, and did not help much with generating client-side HTML or manipulating the DOM. Version 4.0 introduces two major features for simplifying client-side development: client-side data binding and declarative component creation. As we’ll see, the addition of these two features greatly expands the options you have when writing client pages. Additionally, declarative instantiation and templating define a client-side model that is very familiar and therefore easy to use.

As you may be aware, the first release of ASP.NET AJAX had a supplemental futures release that contained an implementation of declarative instantiation and client binding, so we always knew this was coming. However, the earlier implementation was based on XML and required that the user insert a script element marked with the type=’text/xml-script’ attribute below the HTML for the page. While initially very promising, this technique had several drawbacks including its verbosity, its dependence on a client XML parser, and performance issues. Finally in version 4.0, we have a completely new implementation that doesn’t suffer from any of these limitations, and looks to be really useful and easy to use.

This article is based on the preview 4 release of ASP.NET Ajax available for download at http://www.codeplex.com/aspnet/, and thus the details of some features explained here are subject to change before the final release.

DataView and client templates

We will start with a simple example that demonstrates how to associate an array of items in JavaScript with a client template. The core mechanism for client data binding and templating is a client-side class named Sys.UI.DataView. This class inherits from the Sys.UI.Control class which defines a mechanism for associating with an HTML element in the DOM, and it also defines several properties and methods including the data property which can be initialized with an array of data to bind to a template. The page below uses the DataView class to associate a list of courses and their codes to an HTML table template (note we are manually including the script files for ASP.NET Ajax 4.0 – these will be included through the standard ScriptManager control in the final release).

 

<html xmlns="http://www.w3.org/1999/xhtml">

<head>

    <style type="text/css">

        .sys-template {display:none}

    </style>   

    <script src="scripts/MicrosoftAjax.debug.js"

            type="text/javascript"></script>

    <script src="scripts/MicrosoftAjaxTemplates.debug.js"

            type="text/javascript"></script>   

    <script type="text/javascript">

    var courses = [

  { CourseCode: "AP17", Course: "ASP.NET Ajax Fundamentals"     },

  { CourseCode: "AP10", Course: "ASP.NET 3.5 Fundamentals"      },

  { CourseCode: "AP27", Course: "ASP.NET MVC Fundamentals"      },

  { CourseCode: "AP23", Course: ".NET 3.5 Fundamentals"         },

  { CourseCode: "AP25", Course: "LINQ Fundamentals"             },

  { CourseCode: "AP19", Course: "Silverlight Fundamentals"      },

  { CourseCode: "AP14", Course: "WCF Fundamentals"              },

  { CourseCode: "AP16", Course: "Windows Workflow Fundamentals" },

  { CourseCode: "AP15", Course: "WPF Fundamentals"              }

        ];

 

     function pageLoad()

     {

         $create(Sys.UI.DataView,

           { data: courses }, null, null,

           $get("resultTable"));

     }

    </script>

</head>

<body>

    <table id="resultTable" border="1" class="sys-template">        

        <tr>

          <td>{{CourseCode}}</td>

          <td>{{Course}}</td>

        </tr>

    </table>              

</body>

</html>

 

When run, the page above will display the following table of courses:

 

 

As soon as the DataView class is created with the $create() method, and initialized with the courses array as its data property, the data in that array is bound to the template defined by the resultTable element. The entire data binding process is very similar conceptually to the equivalent server-side data binding process most ASP.NET developers are familiar with: a collection of items is bound to a template which is rendered once per element in the collection, replacing any data-bound expressions with data from the current bound element.

There is no equivalent concept to the server-side controls’ ItemTemplate or AlternatingItemTemplate properties in client-side binding. Instead, you specify the identifier of an HTML element in the page whose child elements all constitute the template to be replicated. This keeps the markup simple without introducing any additional syntax, and maintains XHTML-compliance for validation. The one other requirement for defining a template is the parent element must have the sys-template CSS class applied, and that class must be defined with display set to none, as shown in the example above. This convention serves two purposes – it helps the parser identify which elements are part of a template on your page (which will become important when we use declarative instantiation), and it keeps the template markup hidden until ASP.NET Ajax has completed the binding (it will toggle the display to be visible).

Customizing Templates

The first thing you should know about customizing templates, is that the template expression language is JavaScript. This means you can inject arbitrary JavaScript expressions into your template markup, which gives you a lot of flexibility. For example, if we wanted to update our table template to show the course code prefixed to the course name, we could use the JavaScript concatenation operator to generate the string as shown below.

 

   <table id="resultTable" border="1" class="sys-template">        

     <tr>

       <td>{{CourseCode}}</td>

       <td>{{CourseCode + ":" + Course}}</td>

     </tr>

</table>             

 

Even with the entire JavaScript language at your disposal in your binding expressions, however, you will quickly find limitations in what you can achieve. For example, suppose we wanted to include a thead element within our templated table shown above – what would the following end up rendering?

 

<table id="resultTable" border="1" class="sys-template">

      <thead>

          <tr>

            <th>Code</th>

            <th>Course</th>

          </tr>

      </thead>

      <tr>

        <td>{{CourseCode}}</td>

        <td>{{Course}}</td>

      </tr>

</table>      

 

Since the thead element is one of the child elements of the table, which is the container of the template, it will be replicated along with the row template for each item in the bound array, resulting in n head rows which is obviously not what we want. Instead, we need some way to tell the template to render the thead element for only the first element, and ignore it for all others. The solution is to use template code to provide conditional rendering, as shown below.

 

<body xmlns:code="http://schemas.microsoft.com/aspnet/code">

  <!-- ... -->

  <thead code:if="$index==0">

    <tr>

      <th>Code</th>

      <th>Course</th>

    </tr>

  </thead>

  <!-- ... -->

 

The AJAX libraries use the namespace extensibility of XHTML to inject code into the template markup, so before you can use this code feature, you must declare the code namespace on the body tag of your page. With that in place, you can use code-prefixed attributes in any of your template elements, and the templating engine will evaluate the code during the binding process. Notice we are also taking advantage of a pseudo column called $index which refers to the ordinal index of the row being bound (starting at 0). The complete list of code attributes and pseudo columns is shown in the table below.

 

code:if

If the expression evaluates to true, element is rendered, otherwise not.

code:before

The expression is evaluated prior to rendering the element.

code:after

The expression is evaluated after rendering the element.

$index

Ordinal index or the row (0-based).

$dataItem

Current item being bound.

Code attributes and pseudo columns

As a somewhat arbitrary example, here’s a version of our table template that uses code to iterate over each character in a course’s name and convert it into its Morse code equivalent using a function called AsciiToMorse (not shown). The updated rendering is shown below the code sample.

 

<table id="resultTable" border="1" class="sys-template">

  <thead code:if="$index==0">

    <tr>

      <th>Code</th>

      <th>Course</th>

    </tr>

  </thead>

  <tr>

    <td>{{CourseCode}}</td>

    <td>

      <span

        code:before="for(var i=0;i<$dataItem.Course.length;i++){"

        code:after="}"> 

        {{AsciiToMorse($dataItem.Course[i])}}

      </span>

    </td>

  </tr>

</table>

 

Declarative Instantiation

Although there wasn’t a lot of code involved with associating a DataView class with an HTML element, the ASP.NET team wanted to make it possible to uses this new client-side binding mechanism in a completely declarative fashion – without any code whatsoever. What they came up with to achieve this is similar to the original futures implementation of declarative component instantiation using XML script, but this time they implemented it using the namespace extensibility of XHTML. The result is a concise, easy to read, XHTML-compliant syntax that gives you the ability to associate JavaScript components with your HTML elements in a completely declarative fashion.

As an example, here is how we would declare our templatized table to be declaratively associated with a DataView, and bound to the same courses array.

 

<body xmlns:sys="javascript:Sys"

      xmlns:code="http://schemas.microsoft.com/aspnet/code"

      xmlns:dataview="javascript:Sys.UI.DataView"

      sys:activate="*">

   <!-- ... -->

  <table id="resultTable" border="1" class="sys-template"

         sys:attach="dataview"

         dataview:data="{{courses}}">

    <tr>

      <td>{{CourseCode}}</td>

      <td>{{Course}}</td>

    </tr>

  </table>

  <!-- ... -->

 

Notice that we have included two additional namespace mappings on our body element: sys and dataview. We then associate a new instance of the DataView class with our table element using sys:attach and populate the data property of the DataView with the courses array. If there were other parameters we wanted to populate on the DataView, we would add additional dataview-prefixed attributes to our table element with the values we wanted them to take on. The sys:activate attribute added to the body element describes where in the DOM to search for attached JavaScript components. Because we specified ‘*’ the parser will scan the entire page looking for any elements with a sys:attach attribute, and then will take care of creating new instances of the associated class and associating it with the HTML element. If you have a large page, you may want to consider scoping the scan of the parser to a small area by specifying a containing div or other element within which it should restrict its search. With this technique it is now possible to create and associate a DataView with any element on your page, without resorting to writing any script to perform the creation and association.

This declarative instantiation mechanism is not restricted to the DataView class, it in fact works for any client component that inherits from the Sys.UI.Control base class, so you can build your own controls and behaviors and attach them to HTML elements using the same declarative technique. For example, the page below leverages a custom class called PS.HighlightBehavior that adds highlighting behavior to an input element.

 

<html xmlns="http://www.w3.org/1999/xhtml">

<head runat="server">

    <style type="text/css">

        .sys-template {display:none}

        .highlight {background-color:Yellow}

        .lowlight {background-color:White}

    </style>

    <!-- ... -->

    <script src="scripts/HighlightBehavior.js"

            type="text/javascript" />

</head>

<body xmlns:sys="javascript:Sys"

      xmlns:ps="javascript:PS.HighlightBehavior"

      sys:activate="*">

 

    <input type="text" sys:attach="ps"

           ps:highlightclass="highlight"

           ps:lowlightclass="lowlight" /> 

</body>

</html>

Conclusion

ASP.NET Ajax 4.0 is introducing a brand new client templating and data binding model that is intuitive to use, powerful, flexible, and XHTML-compliant. This is a welcome addition to the framework, filling a hole that exists today forcing developers to come up with their own techniques for rendering data to client components. This article described the basic binding and templating mechanism supported by the DataView component, but there is an equal amount that we didn’t explore, including automatic data retrieval from web services and client-side data context classes.

If you'd like to see a demo of these features in action, check out the following screencast:

Also, be sure to watch for coverage of these features and more in Pluralsight On-Demand!

Bio:

Fritz Onion is a co-founder of Pluralsight where he heads the Web development curriculum. Fritz is the author of Essential ASP.NET (Addison Wesley 2003) and Essential ASP.NET 2.0 (Addison Wesley 2006). Reach him at pluralsight.com/fritz.