Data Binding in Dynamic HTML

Accessing data on the Internet using current technology is slow. Pages are slow to render because they are being built by server processes. The processes building these pages are slowing down your server because your server is generating HTML rather than transmitting files. Since, on the client, the data in a page is indistinguishable from the page that contains it, additional requests are made to the server to manipulate the data.

Data binding is a new feature of Microsoft® Internet Explorer 4.0 (IE 4.0) that enables authors to create Web pages that are faster to render, more interactive, easier to author, and that require fewer server resources. It does this by using the Dynamic HTML support built into IE 4.0.

Dynamic HTML allows all the elements on a Web page to be manipulated through scripting languages. Data binding uses Dynamic HTML in conjunction with a simple declarative syntax to display data using standard HTML elements without resorting to complex scripting. Instead of the traditional method of merging the data with the HTML through server-side templates or CGI scripts before it's sent to the browser, data binding performs this operation on the client after a page is received.

Data binding differs from traditional data publishing methodologies in that it uses standard HTML as a template for the data and merges the data with the template asynchronously as the data is transmitted to the client-like rendering a GIF-rather than building the entire page on the server. This results in a page that displays data incrementally as it's transmitted to the client for faster initial response time. It also allows authors to create pages that build client/server applications using HTML elements without creating server-side CGI scripts to process the forms. With data binding, users can manipulate the data on the client without a round-trip to the server and without losing the context of the current page, giving the user a more interactive experience.

A Common Scenario for Data Binding

If you're like me, an example is worth 30 pages of a manual. Consider a fairly common scenario: a brokerage firm that provides access to customers' portfolios through the Web. The customer will want to see a list of the stocks in his portfolio and be able to sort that list by stock symbol, total asset value, number of shares, and so on. The customer may also want to limit the list of stocks viewed to those purchased in a single calendar year.

Before data binding, the author of the Web pages would have had to use CGI scripts or a template processor to construct three pages: one to display a list of stocks in the user's portfolio, another to show the list sorted by symbol, and a third to display the list sorted by asset value. Moreover, to display the list of stocks for a single year, a fourth page would have to be created with an HTML form on it. The user then enters a year using this form and submit it to a server process (CGI or similar) which would then construct a page containing a list of stocks for the year requested. To give the user the ability to sort this new single-year list, the server would have to maintain which year was being viewed so the data could be sorted appropriately. Anyway, you get the idea. Lots of pages, lots of round-trips to the server, and transmission of the same data multiple times over a 28.8 Kbps modem.

If only the brokerage firm had used data binding, they could have created a single page to provide the entire set of functionality described above. The list of stocks in the customer's portfolio would display more quickly because the data would be asynchronously rendered as it was transmitted to the client. Once the data was received by the client, it could be sorted and filtered directly on the client, without a round-trip to the server. The user wouldn't have to wait for the same data to be transmitted over and over again just to change the sort order on the page. Redisplay would be virtually instantaneous.

Building a Page with Data Binding

The best way to understand data binding is to build a page that uses it. I'll do that in this article using the scenario I described in the previous section. Along the way, I'll explain the components of the Dynamic HTML data binding architecture for those of you who like to look under the hood as well as drive the car. The best part is, you'll be able to write this code and experiment on your own today. Data binding is available in the Platform Preview of IE 4.0 at http://www.microsoft.com/ie/ie40. If you still haven't started using it, you may want to download the code now so you can execute as you go.

Data Source Objects

To construct a data-bound page, the first steps are determining the source of the data, the data-manipulation capabilities to give the user, and whether or not the user should be able to update and save the data. These capabilities are provided by data source objects (DSOs).

When designing the data binding architecture for IE 4.0, the design team wanted to ensure that the method for specifying the data on a Web page was as open as possible. The result of this goal was to introduce DSOs for supplying data to the page.

DSOs encapsulate four specific functions. First, they provide an open method for transporting data to the client. A DSO is free to use the protocol and transport of its choice to access the data. Similarly, the DSO determines the method for specifying the data it supplies. It can use SQL, URLs, or any other method it chooses to specify the data set.

Since the DSO is responsible for the transport and specification of the data, it must also be responsible for supporting any manipulations to the data. All sorting, filtering, transformation, and user update support is the responsibility of the DSO, not the server. Generally, DSOs expose data manipulations through methods or properties.

The fourth function of a DSO is to expose an object model for script access. DSOs are free to expose properties, methods, events, and script-accessible objects to provide access to and manipulation of the data they supply. Again, the DSO determines the programming model. No specific model is imposed upon it by the architecture.

You're probably wondering how the DSO exposes the data it supplies to a Web page. This is one area where there is a strict requirement on the DSO: it must provide access to the data through the OLE-DB API. Implementing the OLE-DB API in a DSO is not complicated. DSOs are available written with Java™, using JavaBeans, or as ActiveX controls written in Visual Basic® or Visual C++®. A Data Source Object Gallery will be available on the Microsoft Site Builder Web (http://www.microsoft.com/sitebuilder). Check there for DSOs to use as well as the source code for the DSOs. The details of building a DSO are beyond the scope of this article. Look for future articles that will address this subject in detail.

Inserting a Data Source Object into Your Web Page

Now that I've shown you what a DSO is, let's return to building the sample page. I'll begin by inserting a DSO into the page. First I need to determine which DSO to use. If I were building this page for actual use by a brokerage firm, I would use the Advanced Data Connector (ADC) DSO that ships with IE 4.0. The ADC provides direct access to databases through a server component and ODBC. However, in order to let you run the example that I build and experiment with, I'm going to use the Tabular Data Control (TDC) instead. The TDC also ships with IE 4.0, but it reads its data from a delimited text file. This text file can be output from most DBMSs and is simple to author (it can be typed right in). The TDC also provides the ability to sort and filter the dataset on the client, meeting the requirements for my test application.

The first step for my application is to create a data file. Using Microsoft Access, I've saved some data and created a data file with the Access Export Wizard. The file I've created looks like this:

Symbol,Acquired,Shares,Quote,AssetValue:INT,Chart
IBM,1995,200,137.875,27575,<IMG SRC=StockData/IBM.gif>
MSFT,1995,500,97.125,48562,<IMG SRC=StockData/MSFT.gif>
GM,1996,100,54.25,5425,<IMG SRC=StockData/GM.gif>
T,1995,400,33.50,13400,<IMG SRC=StockData/T.gif>
INTC,1996,300,131.00,39300,<IMG SRC=StockData/INTC.gif>

The Tabular Data Control reads this delimited file and exposes it as a dataset for data binding. The first line in the file defines the column names. Note the :INT appended to the AssetValue column name. This indicates that this column contains integer values and should be sorted as integers rather than as strings.

Once the file is assembled, I can install it somewhere on my Web site. For this example I'll assume that the file resides alongside the HTML file and use a relative URL. The Tabular Data Control is added to my Web page with an <OBJECT> tag:

<OBJECT ID=TDC1 CLASSID="clsid:333C7BC4-460F-11D0-BC04-0080C7055A83" WIDTH=0 HEIGHT=0>
  <PARAM NAME=DataURL Value="StockData.txt">
  <PARAM NAME=TextQualifier Value=",">
  <PARAM NAME=UseHeader Value=True>
</OBJECT>

The DataURL parameter locates the data file. The TextQualifier parameter indicates the character used to separate fields within the file. The UseHeader parameter indicates that the first line of the file contains the column names.

That's all there is to it. The DSO is complete and ready to supply data to the page. The next step is to insert HTML elements bound to this data into the page.

HTML Extensions

In order to bind HTML elements to data supplied by a data source object, IE 4.0 introduces support for three new HTML tag attributes proposed to the World Wide Web Consortium (W3C) for inclusion in the HTML standard: DATASRC, DATAFLD, and DATAFORMATAS. These attributes allow an HTML element to obtain and display its value from a DSO included in the HTML page. Let's look at how I would use these attributes.

DATASRC is used on an HTML element to reference the DSO that supplies the data to the element. DATASRC takes the value of the DSO's ID. Since I've inserted a TDC with the name TDC1, a <SPAN> tag would reference this Tabular Data Control as follows:

<SPAN DATASRC=#TDC1></SPAN>

The <SPAN> tag now references the data source object, but it still needs to reference the column that contains the data it is bound to. DATAFLD was introduced to do this. DATAFLD is used on an HTML element in conjunction with DATASRC to indicate which column of the data contains the bound value. To display the symbol from my example, I'd add DATAFLD to the <SPAN> as follows:

<SPAN DATASRC=#DSC1 DATAFLD=Symbol></SPAN>

Used together, DATASRC and DATAFLD fully qualify a binding. That is, they specify the data source and the name of the data column to bind-all the necessary information. DATASRC and DATAFLD can be used with the following HTML elements:

DIV
SPAN
INPUT-TEXT
INPUT-RADIO
INPUT-CHECKBOX
INPUT-HIDDEN
TEXTAREA
MARQUEE
IMG
SELECT
APPLET
OBJECT
PARAM
TABLE
BUTTON
A
FRAME
IFRAME
LABEL

There is one exception to this rule. Only DATASRC is allowed on a <TABLE> tag. When the DATASRC attribute is specified on a table, the table will be used as a template and be repeated once for each record in the data set. Within the table template, bound elements can be included to display data from the record. For example, I could define the list of stocks in my portfolio using this table:

<TABLE ID=Table1 BORDER DATASRC=#TDC1>
  <TBODY>
    <TR>
      <TD ROWSPAN=2><DIV DATAFLD=Acquired></DIV></TD>
      <TD><SPAN DATAFLD=Symbol></SPAN></TD>
    </TR>
    <TR>
      <TD><SPAN DATAFLD=Shares></SPAN> &nbsp;shares @
          <SPAN DATAFLD=Quote></SPAN> =
          $<SPAN DATAFLD=AssetValue></SPAN>
      </TD>
    </TR>
  </TBODY>
</TABLE> 

Now that I have my list of stocks in the table, I want to add a graph that shows the performance of each stock over time. To do this, I'll add another table cell with a <DIV> inside it. I'll bind this <DIV> to the Chart column from my data. Notice that the Chart column in the data contains an HTML image tag, <IMG>. I can display this image in my <DIV> by using the DATAFORMATAS attribute in addition to DATAFLD. The new table cell would look like this:

<TD ROWSPAN=2><DIV DATAFLD=Chart DATAFORMATAS=HTML></SPAN></TD>

Note that DATAFORMATAS indicates that the data in the column of my data set contains HTML and should be rendered when displayed. DATAFORMATAS can take the values text (for rendering plain text), HTML (for HTML text), and None. DATAFORMATAS is valid on <DIV>, <SPAN>, and <MARQUEE> tags.

Before showing you how to filter by job function and sort by last name, let's take a moment to discuss the final part of the data binding architecture: the internal agents that make the bindings possible.

Binding and Repetition Agents

Internet Explorer provides two internal agents: a binding agent for populating data into the data-bound HTML elements and a repetition agent for expanding repeated tables. When the HTML document is parsed, the binding agent keeps track of all elements containing the DATAFLD attribute, populating these elements with the data from the appropriate column of the data source object. Similarly, it also keeps track of changes made on these data consumers and propagates the changes back to the data source object. The binding agent is thus a synchronization mechanism for maintaining the display and storage of data in the page.

The table repetition agent works in conjunction with the binding agent to repeat the contents of a template table over all records supplied by the data. The table repetition agent detects when DATASRC is included in a <TABLE> and asynchronously populates the page by repeating the table as many times as necessary, passing each instance of the template to the binding agent. The binding agent then accesses the data in the record and actually displays the data in the bound HTML elements. It is worth noting that the binding agent keeps track of all bound elements in every repeated record. Subsequent modification of any data values in any record will then be displayed in the proper location of the repeated table.

In general, you don't have to worry about the table
repetition and binding agents. This nuts and bolts functionality is built into IE 4.0 and does not require any work from the page author.

Adding Sort and Filter-Using Script

Remember that DSOs, not the browser, are responsible for supporting manipulations of the locally cached data. To invoke the sorting and filtering code, I need to write some script code to set properties and call methods on the DSO. I'll start with sorting.

The TDC exposes two properties and one method to enable sorting. The SortAscending property indicates whether the sort order is ascending (true) or descending (false). There is also a SortColumn property that indicates the name of the column to use for sorting. Sorting does not take place when these properties are set. Instead, an additional method, Reset, is provided. This causes the dataset to be sorted based on modifications to the sorting properties. Applying this to my example, I would insert an <INPUT> tag to create a button on my page. The button would have an ONCLICK parameter which would reference the following script:

<INPUT TYPE=BUTTON VALUE="Symbol" ONCLICK=symbol_sort()>
···
<SCRIPT>
      function symbol_sort()
      {
        TDC1.SortAscending=true;
        TDC1.SortColumn="Symbol";
        TDC1.Reset();
      }
</SCRIPT>

When the customer presses the button, the script will set the SortColumn property on the TDC and call the Reset method to sort the data. The data displayed in the repeated table will be automatically refreshed in order to display the sorted data set.

I can apply similar logic to filtering. There are three properties on the TDC to support filtering. The FilterValue is the value to compare against the column specified in FilterColumn property, using the comparison operator contained in the FilterCriterion property. Again, Reset is used to apply
the filter properties to the dataset. To allow the customer to limit the data displayed to a single year, I'll add a text field and button to my example. The customer can type the year of interest into the text field and press the button to
apply the filtering:

<INPUT TYPE=TEXT ID=newyear>
<INPUT TYPE=BUTTON VALUE="Apply Year Filter" ONCLICK=year_filter()>

<SCRIPT>
      function year_filter()
      {
        TDC1.FilterColumn="Acquired";
        TDC1.FilterValue=newyear.value;
        TDC1.FilterCriterion="=";
        TDC1.Reset();
      }
</SCRIPT>

The year_filter script sets the FilterValue on the TDC to the contents of the Textbox filled in by the user. It then specifies the column to use for filtering and the comparison method. In this case, I'll filter the data set to include all rows with an Acquired column equal to the value entered by the customer.

You can set both the filter and sort properties before making a call to Reset. Reset will apply the filter and sort the filtered rows on the column specified. The benefit is that you can use sorting and filtering in conjunction with each other. In my example, I could have displayed only the stocks for 1995 and then sorted them by Asset Value. Correspondingly, I could get the same effect by sorting on Asset Value and then filtering. The sort order and data filter are maintained through subsequent operations.

Similarly, you can specify sort and filter properties on the DSO directly. This is done by using <PARAM> tags of the <OBJECT>. For example, the following would cause the initial dataset to be sorted by Symbol.

<OBJECT ID=TDC1 CLASSID="clsid:333C7BC4-460F-11D0-BC04-0080C7055A83" WIDTH=0 HEIGHT=0>
  <PARAM NAME=DataURL Value="StockData.txt">
  <PARAM NAME=TextQualifier Value=",">
  <PARAM NAME=UseHeader Value=True>
  <PARAM NAME=SortColumn Value="Symbol">
</OBJECT>

Pulling all of the elements together, the final, complete HTML page would look like Figure 1. This page would be rendered as shown in Figure 2. With additional filtering by year, the data displayed would change, as shown in Figure 3.

Figure 1: Stock Portfolio HTML

<HTML>
   <HEAD>
     <TITLE>Stock Portfolio</TITLE>
 
     <SCRIPT>
       function asset_sort()
       {
         TDC1.SortAscending=false; 
         TDC1.SortColumn="AssetValue";
         TDC1.Reset();
       }
 
       function symbol_sort()
       {
         TDC1.SortAscending=true;
         TDC1.SortColumn="Symbol";
         TDC1.Reset();
       }
 
       function year_filter()
       {
         TDC1.FilterColumn="Acquired";
         TDC1.FilterValue=newyear.value;
         TDC1.FilterCriterion="=";
         TDC1.Reset();
       }
 
     </SCRIPT>
 
   </HEAD>
 
   <BODY>
 
     <OBJECT ID=TDC1 CLASSID="clsid:333C7BC4-460F-11D0-BC04-0080C7055A83" WIDTH=0 HEIGHT=0>
       <PARAM NAME=DataURL Value="StockData.txt">
       <PARAM NAME=TextQualifier Value=",">
       <PARAM NAME=UseHeader Value=True>
     </OBJECT>
 
     <P>
 
     Sort by: <INPUT TYPE=BUTTON VALUE="Symbol" ONCLICK=symbol_sort()>
     <INPUT TYPE=BUTTON VALUE="Asset Value" ONCLICK=asset_sort()>
     <P>
     <LABEL FOR=newyear>Enter Year:</LABEL><INPUT TYPE=TEXT ID=newyear>
     <INPUT TYPE=BUTTON VALUE="Apply Year Filter" ONCLICK=year_filter()>
     <P>
 
     <TABLE ID=Table1 BORDER DATASRC=#TDC1>
       <TBODY>
         <TR>
           <TD ROWSPAN=2><DIV DATAFLD=Acquired></DIV></TD>
           <TD><SPAN DATAFLD=Symbol></SPAN></TD>
           <TD ROWSPAN=2><DIV DATAFLD=Chart DATAFORMATAS=HTML></SPAN></TD>
         </TR>
         <TR>
           <TD><SPAN DATAFLD=Shares></SPAN> &nbsp;shares @ <SPAN DATAFLD=Quote></SPAN> = $<SPAN DATAFLD=AssetValue></SPAN></TD>       
         </TR>
       </TBODY>
     </TABLE>
   </BODY>
 </HTML>

Figure 2: The Stock Portfolio Page

Figure 3: Stocks Filtered by Year

Want to Do More?

With this understanding of the basics of data binding, you can play around with adding it to your own Web pages. For instance, try using a data source object to supply data to your page. Use the data binding extensions to specify an HTML template for displaying your data. Write small scripts to support data manipulations on the page. Using these basic concepts, you can build a wide variety of interesting and interactive pages that reduce your server load and increase the usability of the page.

But, this isn't all that data binding can do for you. In fact, I've really only scratched the surface. There are whole areas of functionality I haven't addressed. The following represent just a few possibilities:

Look for follow-up articles on data binding in future issues of Microsoft Interactive Developer. In the meantime, download the Internet Explorer 4.0 Platform Preview from http://www.microsoft.com/ie/ie40 to start experimenting and building pages on your own. You'll find examples of data binding on the IE 4.0 Web site and you'll find detailed information on data binding in the Dynamic HTML section of the Microsoft Internet SDK, available at the same URL.