December 2009

Volume 24 Number 12

Cutting Edge - Live Data Binding in ASP.NET AJAX 4.0

By Dino Esposito | December 2009

Recently I moved into a new office and went through the extremely pleasant and gratifying experience of packing up all the programming books I had collected in more than 10 years.

Those books could tell you quite clearly how Web programming evolved in the past decade, and which technologies followed one another, each improving (and in many cases revolutionizing) the other.

One book in particular caught my attention. It covered cutting-edge (well, for that era) programming techniques for Internet Explorer 4. I couldn’t resist the temptation to flip through its pages.

In the late 1990s, most big names in the computer industry were engaged in their first attempts to make the Web and the browser a dynamic and highly programmable environment.

Data binding was just one of many popular features being researched and developed. While the basic idea of data binding hasn’t changed significantly over the years, a real transformation did occur as far as its application to the Web world. The common approach to implementing data binding over the Web is radically different today than in the late 1990s, and much of the difference is due to Asynchronous JavaScript and XML (AJAX).

In this column I’ll discuss various forms of client-side data binding as they are coming out in ASP.NET AJAX 4.0. In particular, I’ll focus on some advanced features of data binding and observable objects.

Basic Principles

Generally speaking, data binding is simply a program’s ability to bind some members of a target component to the members of a data source. Rapid Application Development (RAD) tools such as Microsoft Access and Microsoft Visual Basic made data binding a successful reality.

RAD tools offered an easy and effective infrastructure for developers to bind visual elements to the members of a data source. For a long time, the data source was uniquely identified with a record-set data stream originating from a SQL query.

In this regard, data binding nicely fits in a smart-client scenario but poses additional issues if employed in a Web-client scenario. For example, how would you flow records from the origin database server down to the requesting JavaScript-equipped browser?

Among many other things, that old book I opened up after years of oblivion discussed the data binding features of IE4 based on a couple of special ActiveX components, aptly named the Tabular Data Control (TDC) and Remote Data Services (RDS) control. Figure 1 illustrates the overall architecture of client-side data binding as it was envisioned by IE4 architects in the beginning of the dynamic Web era.

Figure 1 Client-Side Data Binding in Internet Explorer 4

 A made-to-measure ActiveX control manages the connection with a remote data source and takes care of downloading (and optionally caching) data. The data source is any ODBC-compliant data source with RDS; it’s a server-side text file with TDC.

The actual binding between source and target elements is implemented through browser-specific HTML attributes such as datasrc, datafld and dataformatas. Here’s a quick example:

<span id="Label1" datasrc="#rdsCustomers" datafld="CompanyName" />

The content of the bound field—CompanyName in the example—takes up the space reserved for the SPAN tag in the resulting Document Object Model (DOM).

What does the actual job of inserting data into the DOM? As mentioned, it’s the browser that in this case does the trick. When the browser encounters any dataXXX attributes, it queries the data source control for data using an internal, contracted API. Any data it gets is then inserted into the final DOM and displayed to the user.

As you can see, the solution is strongly browser-specific and understandably never captured the heart of developers.

Client-side data binding was then set aside for a few years as ASP.NET and its server-side programming model gained wide acceptance.

In recent years, the advent of AJAX generated a lot of interest around client-side data binding, and engineers were back at work finding an effective (and this time cross-browser) way to make it happen.

Evolution in ASP.NET AJAX

Figure 2 shows the overall architecture of client-side data binding as it’s implemented in ASP.NET AJAX 4.0.

Figure 2 Client-Side Data Binding in ASP.NET AJAX 4.0

Although the architectures depicted in Figure 1 and Figure 2 may look similar at first glance, they actually differ in a number of key aspects.

First and foremost, with ASP.NET AJAX 4.0 you can build client-side data-binding solutions that work with any modern browser. The glue code required to actually bind source data to target elements is now part of the Microsoft Ajax JavaScript library. As such, it can be hosted in any browser.

Furthermore, for binding you no longer have proprietary and non-standard HTML attributes such as datasrc and datafld that the browser must resolve. Instead, binding information is specified using XHTML-compliant, namespaced custom attributes resolved by code in the JavaScript library. It can also be done imperatively.

Old-Style versus New-Style

Another significant difference lies in the structure of the data source object. In old-style data binding, you use a sort of black-box proxy that manages data retrieval for you. In ASP.NET AJAX 4.0, you don’t need any such ActiveX or binary components. All you need is a JavaScript object with the source data.

The built-in binding infrastructure links together fields on the JavaScript source object and elements of the DOM.

In ASP.NET AJAX 4.0, such a binding infrastructure is built into the Sys.UI.DataView component. Functionally speaking, the DataView object operates in much the same way as the RDS control does in IE4-style client data binding. It connects directly to a remote endpoint to get and expose data.

However, there are some differences. The DataView object is a client control entirely written in JavaScript that requires no special support from the browser to run. As you can see, it’s quite different from the RDS ActiveX control.

Moreover, the DataView control doesn’t directly interface with a relational data source. Instead, it connects to any JavaScript Object Notation (JSON)- or JSON With Padding (JSONP)-enabled service, such as a Windows Communication Foundation endpoint, and exchanges data using JSON. The service can wrap any physical data store (including a relational database) or even be a plain wrapper around an Entity Framework model. As Figure 2 illustrates, in ASP.NET AJAX 4.0 you can even have data binding in place without an outbound network connection to the server. If, say, upon loading, a page downloads some data onto the client machine, you can have data binding at work on locally cached data without any further roundtrip to the server.

A Brief Summary

In the October 2009 installment of the Cutting Edge column (msdn.microsoft.com/magazine/ee309508.aspx), I covered the basics of data binding in ASP.NET AJAX 4.0 from a developer’s perspective. While you can still refer to that article for deep coverage, I’m going to provide here a brief summary of the most important programming facts for client data binding.

In ASP.NET AJAX 4.0, client-side data binding can occur within a proper HTML template. A template is a DOM tree decorated with the sys-template CSS attribute:

<div sys:attach="dataview1" class="sys-template">  
   ...
</div>

The sys-template is a conventional name for a user-defined CSS style that at the very minimum includes the following:

<style type="text/css">
   .sys-template { display:none; }
</style>

Decorating a given HTML tag with the sys-template attribute is not enough, however. You must also add some behavior to the tag that enables it to process any binding expressions inside. In this context, a behavior is just an instance of a made-to-measure JavaScript component or control.

A behavior can be attached to an HTML tag, either by instantiating the behavior programmatically or by using a declarative approach (by adding markup to the template tags in the page). For the declarative approach, the behavior must be associated with a public name (namespace prefix).

Here’s an example of assigning a public name to an instance of the DataView component:

<body xmlns:sys="javascript:Sys" 
      xmlns:dataview1="javascript:Sys.UI.DataView">
...
</body>

The sys:attach attribute gets a public name and creates an instance of the referenced behavior object. In the first code example in this section, the DIV tag is empowered with the behavior expressed by the object named dataview1. As you can guess, dataview1 is just the public name of the Sys.UI.DataView JavaScript object. 

Once a DataView instance has been attached to an ASP.NET AJAX 4.0 template, the DataView can successfully process any binding expressions contained in the templates. Here’s a sample template with the simplest binding syntax:

<ul id="imageListView" class="sys-template" 
     sys:attach="dataview1" 
    dataview1:data="{{ imageArray }}">
    <li>
        <span>{{ Name }}</span>
        <span>{{ Description }}</span>
    </li>
</ul>

The {{expression}} token tells the DataView to process the embedded JavaScript expression and assign the result to the DOM or the specified DataView property. For example, the code above assigns the content of a JavaScript variable named imageArray to a DataView property named data. In this way, you define the data source of the binding operation. This information is used to expand any other binding expressions within the template, such as those used above in the body of the two SPAN tags. Name and Description are expected to be public properties on the data item or items assigned to the data property of the DataView.

Inline Expression Evaluation

The {{expression}} syntax indicates the simplest type of binding supported by ASP.NET AJAX 4.0. Any bindings expressed in this way are evaluated only when the template is rendered. They are never updated unless the template is refreshed programmatically.

An inline expression is evaluated against the current state of the data source at rendering time, but doesn’t automatically capture any further changes made to the data source.

An alternative, richer binding model is also supported that gives you the same programming power of XAML data binding in Windows Presentation Foundation and Silverlight applications. Such a set of advanced data binding features are commonly referred to as live binding. Let’s find out more.

Live Binding

Live binding ensures that the value displayed in the user interface is automatically updated any time the bound value in the data source changes. For example, suppose you establish a live binding between a SPAN tag and the CompanyName property in a data source. The SPAN tag displays the current value of the CompanyName property at the time of rendering. However, the content of the SPAN tag will be automatically updated any time the bound data source property undergoes changes. Live binding can be applied to any two objects, whether DOM elements or JavaScript objects.

A different syntax is required for live binding expressions. Here’s an example:

<span>{binding CompanyName}</span>

You use a single pair of curly brackets to wrap the expression, and prefix it with the keyword binding. As you can see, the overall syntax has much in common with the equivalent XAML syntax, and that isn’t coincidental.

It should be noted that the content of the SPAN tag shown earlier is updated whenever a change is detected on the currently bound data item; the reverse won’t work. If the content of the SPAN is updated, that change won’t be propagated to the source object.

Live binding also can be described as a one-way binding that may happen repeatedly as updates on the data source are detected.

Hold on! The strategy employed to detect changes on bindings is a key point and I’ll have more to say about it in a moment, but not before introducing two-way binding.

Two-Way Data Binding

Two-way data binding is a special form of live binding that uses two channels to detect changes on the binding. When two-way binding is in place between two objects, the following happens:

  • If the data source changes, the target object is automatically refreshed.
  • If the target object changes, the new state is propagated to the underlying data source.

Put another way, two-way data binding ensures that the source and target objects are always in sync.

No Tier Crossing

The following may perhaps sound like a foregone conclusion, but let me make it clear anyway. Imagine you have two-way binding between a piece of user interface and some data that a service retrieved from a database.

The data downloaded from the server and bound to the visual elements of the user interface represent a snapshot of the domain model. Say, for example, it represents a Customer object. If the displayed Customer object is modified in a two-way binding page, then all detected changes are mirrored to the client-side Customer object, but in no way will they be propagated to the server. Two-way data binding doesn’t cross any tiers. 

In terms of syntax, two-way binding is nearly the same as one-way live binding.

An ASP.NET AJAX binding is expressed via a Sys.Binding JavaScript object. You can control the direction of the data flow through the mode attribute on the Sys.Binding object that the framework creates for you any time you use the live binding syntax. (Note that no Sys.Binding object is created when you opt for plain {{...}} inline expressions.)

The following code snippet shows how to set up two-way data binding using the mode attribute:

<span id="Label1">{binding CompanyName, mode=twoWay}></span>

Possible values for the mode attribute are summarized in Figure 3.

Member Value Description
auto 0 Data flow is twoWay if the target is an input element, select element, textArea element or component that implements the Sys.INotifyPropertyChange Interface. Data flow is oneWay otherwise.
oneTime 1 Data is transferred from the source object to the target only one time when the template is rendered.
oneWay 2 Data is transferred from the source object to the target whenever the source is updated.
twoWay 3 Data is transferred from the source object to the target whenever the source is updated, and from target to source whenever the target is updated.
oneWaytoSource 4 Data is transferred from target to source whenever the target is updated.

Figure 3 The Sys.BindingMode Enumeration

Live Binding in Action

Figure 4 shows sample code that demonstrates live, two-way data binding. The page contains one template that is rendered using a DataView control. The data source object is a JavaScript array named theCustomers. Don’t be fooled by the fact that theCustomers is a local object statically defined within the client browser. What really matters is that theCustomers is ultimately assigned to the data property of the DataView object. The DataView object has a rich programming interface that allows you to put into the data property any content, including content downloaded from a Web service.

<asp:Content ID="Content2" runat="server" ContentPlaceHolderID="PH_Head">
  
    <link rel="stylesheet" type="text/css" 
      href="../../Css/lessantique.css" />
    <style type="text/css">
        .sys-template { display:none; }
    </style>
    
    <script type="text/javascript">
        var theCustomers = [
           { ID: "ALFKI", CompanyName: 
            "Alfred Futterkiste" },
           { ID: "CONTS", CompanyName: 
           "Contoso" }
        ];
    </script>
</asp:Content>    

<asp:Content ID="Content5" 
  ContentPlaceHolderID="PH_Body" 
  runat="server">

    <asp:ScriptManagerProxy  
    runat="server">
        <Scripts>
          <asp:ScriptReference Path=
"https://ajax.microsoft.com/ajax/beta/0910/MicrosoftAjaxTemplates.js" />
        </Scripts>
    </asp:ScriptManagerProxy>

    <div id="customerList">
       <ul class="sys-template" 
         sys:attach="dataview" dataview:data="{{ theCustomers }}">
         <li>
           <span><b>{binding ID}</b></span>
           <input type="text" id="TextBox1" 
             value="{binding CompanyName}" /> 
           <br />  
           <span>Currently displaying... 
<b>{binding CompanyName}</b></span>  
         </li>
       </ul>
    </div>
</asp:Content>

Figure 4 Live, Two-Way Binding Sample

For each bound data item, the template emits an LI tag that includes a text box. The text box is bound to the CompanyName property of the source. In the same template, a SPAN tag is also bound to the CompanyName property of the source.

Note that live bindings are not limited to the template they belong to. You can have the same expression—say, {binding CompanyName}—in two different templates. As long as the same data source object (or a compatible object) is attached to both templates, the binding will always be correctly resolved. Figure 5 shows the page in action.

Figure 5 Live Binding in Action

Initially the text box and the SPAN tag contain the same data. However, at some point the user may start editing the name of the company in the text box. Nothing happens until the user tabs out of the text box.

The editing phase is considered complete as soon as the text box loses focus. At this point, the two-way data binding mechanism triggers and updates the underlying data source object. Because the SPAN tag is also bound to the same data property through live binding, any changes are propagated.

To prevent the automatic update of the data source when an INPUT element is involved, you set the mode property explicitly, as shown below:

<input type="text" value="{binding CompanyName, mode=oneWay}" />

Enter this change to the code in Figure 4 and see the difference.

Detecting Changes

When the mode property of a binding is not set explicitly, it takes the auto value as described in Figure 3. So when you attach a binding to any HTML elements that refer to input scenarios (such as INPUT, SELECT or TEXTAREA), the property mode defaults to twoWay. As a result, all the changes to the target made via the browser’s user interface are automatically transferred to the source.

Note that there are two variations of a oneWay binding. The standard oneWay binding detects changes in the source and reflects them in the user interface. The alternate oneWayToSource does the reverse: it detects changes in the target and reflects them in the source object. Try using the following code:

<input type="text" value="{binding CompanyName, mode=oneWayToSource}" />

The initial display of the page will contain empty text boxes. As you type, though, the new text is detected and processed as expected.

The two-way data binding option is also the default option for any bound JavaScript object that happens to implement the Sys.INotifyPropertyChange interface. (The interface is part of the Microsoft Ajax JavaScript library.)

When I first introduced live binding, I said that the target is updated whenever the source changes. The following explains which changes the framework can detect and how.

HTML input elements fire standard events when their state is changed or, at a minimum, they notify when they enter or exit an editing phase. Because these events are part of the HTML standard, any data binding solution based on that standard will work on any browsers.

For an update to one side of the binding to be reflected in the other, it has to be done in a way that is possible to detect. Suppose you have a binding where the source is a JavaScript array, as shown here:

<ul class="sys-template" sys:attach="dataview" 
    dataview:data="{{ theCustomers }}">
  <li>
     <span ><b>{binding CompanyName}</b></span>
  </li>
</ul>

Try to update the CompanyName property on an object within the array. The markup shows a button that if clicked runs the enterChanges JavaScript function, shown here:

<span>{binding CompanyName}</span>
<input type="button" value="Enter changes" 
onclick="enterChanges()" />
...
<script type="text/javascript">
    function enterChanges() {
        theCustomers[0].CompanyName = 
       "This is a new name";
    }
</script>

The enterChanges function updates the CompanyName property on the first object in the array. As you can see, this clearly is an operation that updates the state of a bound object.

In the case of live binding, you should expect the SPAN tag to display the new value. If you try that, though, you will see that nothing happens.

That is because there is no cross-browser way to be notified of updates occurring to a plain old JavaScript object such as that. So changes happen but the binding isn’t aware of them and the user interface isn’t refreshed.

Would polling the state of a plain JavaScript object be a viable solution? Probably not, and the development team reasonably ruled out that option, essentially for scalability reasons.

In the end, is using input HTML elements bound to data the only possibility for making data changes in a way that will successfully trigger other live bindings? Well, not exactly. The Microsoft Ajax JavaScript library features a static API through which you can "observe" the changes of any JavaScript object. This API is also available in a flavor that transforms a plain JavaScript object into an observable object for the binding machinery to detect updates.

Observable JavaScript Objects

An observable JavaScript object is an object endowed with additional functionality that raises change notifications when modified. Additional functionality is codified through the Sys.Observer interface. Note that changes made directly, without going through the interface, will not raise change notifications and will be ignored by the binding infrastructure.

Observable objects fit perfectly in a scenario where you want to establish live bindings between visual elements and JavaScript objects, such as those you might get from a remote Web service.

There are two ways to work with observable objects. One entails that you make a given object observable by adding some dynamic code to it—not enough to make a plain JavaScript object a complex thing, but enough to add new capabilities. Here is an example:

<script type="text/javascript">
    var theCustomers = [
            { ID: "ALFKI", CompanyName: 
            "Alfred Futterkiste" },
            { ID: "CONTS", CompanyName: 
            "Contoso" }
        ];    
    function pageLoad() {
        Sys.Observer.makeObservable(theCustomers);
    }
    
    function onInsert() {
        var newCustomer = { ID: "ANYNA", 
        CompanyName: "AnyNameThatWorks Inc" };
        theCustomers.add(newCustomer);
    }
</script>

The Sys.Observer.makeObservable method takes a JavaScript object (including arrays) and adds methods to it that you can use to make changes to the object that the bindings can detect. Note that having an observable array provides methods for changing the array in an observable way—so you can detect insertions and deletions. But it does not automatically provide the corresponding methods for modifying the properties of the individual items in the array in an observable way. For that, you can separately call makeObservable on the individual items, and they will then also have additional methods added.

 As I mentioned earlier, the following code associated with a click event won’t trigger the binding:

<script type="text/javascript">
    function enterChanges() {
        theCustomers[0].CompanyName = 
        "This is a new name";
    }
</script>

This code, however, will trigger the binding:

<script type="text/javascript">
    function enterChanges() {
       System.Observer.setValue(theCustomers[0], 
       "CompanyName", "New name");
    }
</script>

What if the observed object has child objects? No worries: the setValue method knows how to handle the "dotted" syntax:

System.Observer.setValue(theCustomers[0], "Company.Address.City", "Rome");

Finally, note that the observer pattern can be applied to any object you may encounter in the context of a Web page, including DOM elements, behaviors and even browser objects such as window.

Static and Dynamic

Most times when you need data binding in an application, you also need it to be live, at least one-way, if not two-way. In ASP.NET AJAX 4.0, data binding can be both static—that is, a simple inline evaluation of data values during rendering—and dynamic, in the sense that it can detect changes in source or target and apply them.Not all updates can be detected and used to refresh bindings. ASP.NET AJAX 4.0 easily recognizes changes entered into bound objects through visual elements. But for changes entered programmatically into JavaScript objects or arrays, there’s no reliable cross-browser way to have live detection of changes. The trick in ASP.NET AJAX consists of providing a way to make changes so that they’re observable and thus can be detected by live bindings. This takes the form of appending some observable operations to the object or, as an alternative, using ad hoc Sys.Observer static methods to conduct updates.   


Dino Esposito is the author of the upcoming “Programming ASP.NET MVC 2” (Microsoft Press, 2010). Based in Italy, Esposito is a frequent speaker at industry events worldwide.

Thanks to the following technical experts for reviewing this article:Dave Reed and Boris Rivers-Moore