The Tabular Data Control

The tabular data control (TDC) is a built-in ActiveX control. Instead of getting its data from a standard database, this DSO uses a delimited text file as a source of data. Delimited text simply means the data is in a text file in which data items and data rows are separated by common entities. For example, in the text Dill|Anethum graveolens|Culinary and Medicinal, each data item is separated by the pipe character (|). Another common type of delimited text file is known as a comma-separated-values file, or CSV.

Let's look at a more detailed data sample.

 Angelica                Angelica archangelica     Culinary Basil                   Ocimum   basilicum        Culinary and Medicinal Basil, Cinnamon         Ocimum   basilicum        Culinary and Medicinal Basil, Holly            Ocimum   basilicum        Culinary and Medicinal Basil, Spicy Globe      Ocimum   basilicum        Culinary and Medicinal 

Each item in the tabular text above is a field, and a horizontal group of fields is called a row. If we convert this database table to a delimited text file using the pipe character as the field delimiter and the newline character as the row delimiter, the result looks like this:

 Angelica|Angelica archangelica|Culinary Basil|Ocimum basilicum|Culinary and Medicinal Basil, Cinnamon|Ocimum basilicum|Culinary and Medicinal Basil, Holly|Ocimum basilicum|Culinary and Medicinal Basil, Spicy Globe|Ocimum basilicum|Culinary and Medicinal 

Notice that each horizontal row in the table becomes a line in the text file. Of course, the different characters you choose for delimiters depend on what data you expect in the fields. For example, if you expect a data item to contain multiple lines of text, you might not want to use the newline character as a row delimiter. A text qualifier (covered later in the chapter) is an optional type of delimiter that can help ensure that a whole field is treated as one data item.

Binding Data to a Single-Value Element

Despite the word "tabular" in its name, the tabular data control supports single-value data as well as tabular data. Our first example demonstrates how to use the TDC to bind data to a single-value HTML element. In this example, we will use the above herb data to fill a SPAN element. The data file herbs.txt is the delimited text file with our information about the herbs.

In this file, we use two delimiters: a text qualifier (the exclamation point, !) and a field delimiter (the pipe character, |). The text qualifier specifies the boundaries for each block of text, allowing us to include items in our text that might be used elsewhere as delimiters. (See the sidebar "Understanding Delimiters" for more information.) The field delimiter specifies the boundaries for each field in a record.

Understanding Delimiters
At first glance, it might seem like text qualifiers and field delimiters serve the same purpose, but in fact they are quite different. By using both kinds of delimiters, developers are free to use almost any character they want in text, including characters used as delimiters elsewhere in the data file. For example, imagine a data file in which the pound sign (#) is used as a field delimiter and the exclamation point (!) is used as a text qualifier. If you needed to include the pound sign in one text field, you could enclose it inside a text qualifier and it would be displayed as text rather than interpreted as a field delimiter. Thus, the data #!This is the pound # sign!# would be treated as a single piece of data containing This is the pound # sign.

Our TDC examples will all use the herbs.txt file, which is included on the CD as chap20\herbs.txt. Here are the first 15 lines of herbs.txt. Note the difference between the first row (known as the header row) and the successive lines of text.

 common|botan|usage !Angelica!|!Angelica archangelica!|!Culinary! !Basil!|!Ocimum basilicum!|!Culinary and Medicinal! !Basil, Cinnamon!|!Ocimum basilicum!|!Culinary and Medicinal! !Basil, Holly!|!Ocimum basilicum!|!Culinary and Medicinal! !Basil, Spicy Globe!|!Ocimum basilicum!|!Culinary and Medicinal! !Bay!|!Laurus nobilis!|!Culinary! !Laurel, Sweet!|!Laurus nobilis!|!Culinary! !Borage!|!Borago officinalis!|!Culinary and Medicinal! !Burnet!|!Sanguisorba minor!|!Culinary! !Catnip!|!Nepeta cataria!|!Culinary! !Catmint!|!Nepeta cataria!|!Culinary! !Chamomile!|!Chamaemelum nobile!|!Medicinal! !Chervil!|!Anthriscus cerefolium!|!Culinary! !Chives!|!Allium schoenoprasum!|!Culinary and Medicinal! 

Now that you have seen the herbs.txt file, let's look at the HTML code for our first and most basic example, shown in Code Listing 20-1. Figure 20-1 shows the results of running the code. Note that even though the text Angelica does not appear in the HTML source of the code listing, it is displayed on screen because it is read from the data file.

Code Listing 20-1.

 <HTML> <HEAD> <TITLE>Code Listing 20-1</TITLE> <OBJECT ID="herbTDC" CLASSID="CLSID:333C7BC4-460F-11D0-BC04-0080C7055A83">   <PARAM NAME="TextQualifier" VALUE="!">   <PARAM NAME="FieldDelim" VALUE="|">   <PARAM NAME="DataURL" VALUE="herbs.txt">   <PARAM NAME="UseHeader" VALUE="true"> </OBJECT> </HEAD> <BODY> <B>Common Name-</B><SPAN DATASRC="#herbTDC" DATAFLD="common"></SPAN> </BODY> </HTML> 

The OBJECT element at the top of the page sets up the TDC as our DSO and specifies a number of parameters, including herbs.txt as the target data file. The first column of the herb data file lists the herbs by their common names. This column is bound to the SPAN element. Notice that the <SPAN> tag in Code Listing 20-1 contains the DATASRC attribute,

Figure 20-1. A single-value HTML element is bound to a data file.

which identifies the data source (the DSO) by its ID. Notice also that the syntax for the data source ID requires that a pound sign (#) precede the object name. The DATAFLD attribute identifies the data field (the column) to which the SPAN element is bound—in this case, the column named common.

The DSO knows the names of the columns in the database because they are defined in the data file. The column names appear in the first line of the herbs.txt file, where they are surrounded by field delimiters only, not by text qualifiers. Because we set the DSO's UseHeader property to true in a <PARAM > tag, the DSO knows to use the first line of the text file for column names. If you have not set up column names and your file contains only data, you can refer to a field by its column number. For example, instead of using DATAFLD=
"common"
we could have used DATAFLD="Column1". Remember that for column numbers to function properly, the UseHeader property cannot be set to true.

Of course, our data file contains more than just the common name of the first herb; not only does the record contain the herb's botanical name and some information about its prevalent usage, there are also many different varieties of herbs represented. Code Listing 20-2 demonstrates how to display this information, how to move from one record to another in the database, and how to access the data through script.

Code Listing 20-2.

 <HTML> <HEAD> <TITLE>Code Listing 20-2</TITLE> <OBJECT ID="herbTDC" CLASSID="CLSID:333C7BC4-460F-11D0-BC04-0080C7055A83">   <PARAM NAME="TextQualifier" VALUE="!">   <PARAM NAME="FieldDelim" VALUE="|">   <PARAM NAME="DataURL" VALUE="herbs.txt">   <PARAM NAME="UseHeader" VALUE="true"> </OBJECT> <SCRIPT LANGUAGE="JavaScript" FOR="window" EVENT="onload">   herbRS=herbTDC.recordset   herbRS.MoveFirst() </SCRIPT> <SCRIPT LANGUAGE="JavaScript"> function displayInfo(){   CurPos=("Record "+herbRS.AbsolutePosition+" of "+herbRS.RecordCount)   CurVal1=("\nField 1=" + herbRS.fields(`common') )   CurVal2=("\nField 2=" + herbRS.fields(`botan') )   CurVal3=("\nField 3=" + herbRS.fields(`usage') )   alert(CurPos+CurVal1+CurVal2+CurVal3) } </SCRIPT> </HEAD> <BODY> <INPUT TYPE="button" VALUE="<<" onclick="herbRS.MoveFirst()"> <INPUT TYPE="button" VALUE="<"   onclick="herbRS.MovePrevious();if(herbRS.BOF)herbRS.MoveFirst()"> <INPUT TYPE="button" VALUE="Display Info" onclick="displayInfo()"> <INPUT TYPE="button" VALUE=">"   onclick="herbRS.MoveNext();if(herbRS.EOF)herbRS.MoveLast()"> <INPUT TYPE="button" VALUE=">>" onclick="herbRS.MoveLast()"> <P><B>Common Name-</B><SPAN DATASRC="#herbTDC" DATAFLD="common"></SPAN> <P><B>Botanical Name-</B><SPAN DATASRC="#herbTDC" DATAFLD="botan"></SPAN> <P><B>Usage-</B><SPAN DATASRC="#herbTDC" DATAFLD="usage"></SPAN> </BODY> </HTML> 

click to view at full size.

Figure 20-2. All columns of the record are displayed, and controls that let you move through and examine the data are added.

To display the information about each herb, more SPAN elements were added below the original one and bound to the appropriate columns in the data file. Because each SPAN element is bound to a different data field, the data fields for a record are displayed in their respective SPAN elements each time the TDC moves to a new record.

A script is run when the page is loaded that sets the variable herbRS to reference the recordset child object of the herbTDC object. All DSOs support the recordset object, which can be used to navigate through the data and to insert, delete, and update records.

At the top of the page, four directional buttons, labeled <<, <, >, and >> let the user browse through the herb names in the data file. Depending on which button the user clicks, the MoveFirst, MovePrevious, MoveNext, or MoveLast function of the recordset object is called, and the current display is changed. You've probably noticed the extra code on the < and > buttons in Code Listing 20-2. This code tests the BOF (beginning of file) and EOF (end of file) properties of the recordset object, letting us know where we are in the file and preventing us from moving outside the recordset boundaries.

The Display Info button runs the displayInfo function. This function collects information about the current position in the recordset and then displays it in an alert box. The AbsolutePosition property contains the current position in the recordset. This property can also be set to a particular numeric value to jump to that row in the data. The RecordCount property contains the total number of rows in the database. The fields method of the recordset object returns the value of a particular field of data in the current row of the data.

HTML Elements That Support Single-Value Data Binding

Internet Explorer includes support for binding data to many common HTML elements in addition to SPAN. Table 20-1 lists HTML elements that support data binding, describes what aspect of the element is bound, and indicates whether the element supports the ability to update data in the recordset. All the elements included in this table support single-value data; only the TABLE element (not listed in the table but discussed in the next section) supports tabular data.

Table 20-1 HTML Elements That Support Single-Value Data Binding

HTML Element DSO Binds To Supports Updating
A HREF No
APPLET Property value of <PARAM> Yes
BUTTON innerText, innerHTML No
DIV innerText, innerHTML No
FRAME SRC No
IFRAME SRC No
IMG SRC No
INPUT TYPE=checkbox CHECKED Yes
INPUT TYPE=hidden VALUE Yes
INPUT TYPE=label VALUE Yes
INPUT TYPE=password VALUE Yes
INPUT TYPE=radio CHECKED Yes
INPUT TYPE=text VALUE Yes
LABEL innerText, innerHTML No
MARQUEE innerText, innerHTML No
SELECT text property of currently selected OPTION Yes
SPAN innerText, innerHTML No
TEXTAREA VALUE Yes

Binding Data to a TABLE Element

In the previous section, you saw how the ability to display record data in single-value HTML elements gives the developer and the user more options and greater control over the data. But what if you need to display an entire recordset? Two quite labor-intensive approaches would be either to create a separate data-bound element for every field in every row of data or to write some script that would explicitly create a Web page with all the necessary elements. Fortunately, there is a much easier way. Using the HTML <TABLE> tag, you can render all the fields of data in a DSO with very little work.

Code Listing 20-3 shows the extensive amount of code required just to build a table of five herb records without using data binding. Figure 20-3 shows the table produced by this code.

Code Listing 20-3.

 <HTML> <HEAD> <TITLE>Code Listing 20-3</TITLE> </HEAD> <BODY> <TABLE BORDER="1" CELLSPACING="0">    <THEAD>     <TR>       <TD><B>Common Name</B></TD>       <TD><B>Botanical Name</B></TD>       <TD><B>Usage</B></TD>     </TR>   </THEAD>     <TR>       <TD>Angelica</TD>       <TD>Angelica archangelica</TD>       <TD>Culinary</TD>     </TR>     <TR>       <TD>Basil</TD>       <TD>Ocimum basilicum</TD>       <TD>Culinary and Medicinal</TD>     </TR>     <TR>       <TD>Basil, Cinnamon</TD>       <TD>Ocimum basilicum</TD>       <TD>Culinary and Medicinal</TD>     </TR>     <TR>       <TD>Basil, Holly</TD>       <TD>Ocimum basilicum</TD>       <TD>Culinary and Medicinal</TD>     </TR>     <TR>       <TD>Basil, Spicy Globe</TD>       <TD>Ocimum basilicum</TD>       <TD>Culinary and Medicinal</TD>     </TR>   </TABLE> </BODY> </HTML> 

click to view at full size.

Figure 20-3. A table of data constructed without using data binding.

Data binding simplifies the programming process by significantly reducing the amount of code needed to build a table of data. With data binding, all 60 records in the data file can be shown with less code than it took to show just five records in a table built by hand. The code shown in Code Listing 20-4 uses data binding. Figure 20-4 shows the table that results when this code is executed. You'll notice that except for the size, the two displayed tables are basically the same.

Code Listing 20-4.

 <HTML> <HEAD> <TITLE>Code Listing 20-4</TITLE> <OBJECT ID="herbTDC" CLASSID="CLSID:333C7BC4-460F-11D0-BC04-0080C7055A83">   <PARAM NAME="TextQualifier" VALUE="!">   <PARAM NAME="FieldDelim" VALUE="|">   <PARAM NAME="DataURL" VALUE="herbs.txt">   <PARAM NAME="UseHeader" VALUE="true"> </OBJECT> </HEAD> <BODY> <TABLE DATASRC="#herbTDC" BORDER="1" CELLSPACING="0">    <THEAD>     <TR>       <TD><B>Common Name</B></TD>       <TD><B>Botanical Name</B></TD>       <TD><B>Usage</B></TD>     </TR>   </THEAD>    <TR>     <TD><SPAN DATAFLD="common"></SPAN></TD>     <TD><SPAN DATAFLD="botan"></SPAN></TD>     <TD><SPAN DATAFLD="usage"></SPAN></TD>   </TR> </TABLE> </BODY> </HTML> 

If you wanted to update the contents of the table constructed by Code Listing 20-3 on the previous page (without data binding), you would need to change each cell of the table in the HTML code. To modify the table constructed by Code Listing 20-4 (with data binding), you would simply need to change the data file. For example, a modified data file could contain herb information written in a language other than English. This would prevent the translators from having to interact with the HTML code.

click to view at full size.

Figure 20-4 A table of data constructed with data binding.

Manipulating Data

The data can be manipulated in a number of ways once it is on the Web page. For example, data can be sorted, filtered, changed, added, and deleted.

Sorting and Filtering

The TDC is one DSO that supports both sorting and filtering operations. As you can see below, Code Listing 20-5 shows how we enhanced our herb Web page to allow the user to sort the list by common name, botanical name, or usage, and to filter the entire list by particular type of usage. The page now includes a list box for each action (sorting and filtering). When one of the list boxes is changed, the appropriate action is carried out. Figure 20-5 shows the table after it has been sorted by common name and filtered to display only those herbs used for both culinary and medicinal purposes.

Code Listing 20-5.

 <HTML> <HEAD> <TITLE>Code Listing 20-5</TITLE> <OBJECT ID="herbTDC" CLASSID="CLSID:333C7BC4-460F-11D0-BC04-0080C7055A83">   <PARAM NAME="TextQualifier" VALUE="!">   <PARAM NAME="FieldDelim" VALUE="|">   <PARAM NAME="DataURL" VALUE="herbs.txt">   <PARAM NAME="UseHeader" VALUE="true"> </OBJECT> </HEAD> <BODY> <B>Sort by:</B> <SELECT onchange="herbTDC.Sort=(`+'+this.value); herbTDC.Reset()">   <OPTION VALUE="">None</OPTION>   <OPTION VALUE="common">Common Name</OPTION>   <OPTION VALUE="botan">Botanical Name</OPTION>   <OPTION VALUE="usage">Usage</OPTION> </SELECT> <B>Filter by:</B> <SELECT onchange="herbTDC.Filter=(`usage=`+this.value); herbTDC.Reset()">   <OPTION VALUE="">None</OPTION>   <OPTION VALUE="Culinary">Culinary</OPTION>   <OPTION VALUE="Medicinal">Medicinal</OPTION>   <OPTION VALUE="Culinary and Medicinal">Culinary and Medicinal</OPTION> </SELECT> <P> <TABLE DATASRC="#herbTDC">    <THEAD>     <TR>       <TD><B>Common Name</B></TD>       <TD><B>Botanical Name</B></TD>       <TD><B>Usage</B></TD>     </TR>   </THEAD>     <TR>       <TD><SPAN DATAFLD="common"></SPAN></TD>       <TD><SPAN DATAFLD="botan"></SPAN></TD>       <TD><SPAN DATAFLD="usage"></SPAN></TD>     </TR> </TABLE> </BODY> </HTML> 

In Code Listing 20-5, the sorting and filtering arguments are kept in the two SELECT elements. When the user selects an option in one of the list boxes, first either the Sort or the Filter property of the TDC is set, and then the Reset method is called to reload the data based on the new settings for the Sort or Filter property.

The Sort property can be set to sort by single or multiple columns and in ascending or descending order. To sort in ascending order by the common field, you can specify herbTDC .Sort="+common" and then use herbTDC.Reset() to apply the sort string. To sort in ascending order by usage and then in descending order by common, you can specify herbTDC .Sort="+usage; -common".

The Filter property allows for the displayed data to be limited to a specific subset of the overall data. An example of a simple filter would be herbTDC.Filter="usage=Culinary". It would display only items with a value in the usage column of Culinary. A more complex filter would be herbTDC.Filter="usage<>Culinary & (common=Oregano | common>Sage)", which would display only items in which the usage field was not equal (<>) to Culinary and (&) the common field either contained Oregano or ( | ) came after Sage in the alphabet. More information about complex filtering can be found on the SBN Workshop Web site and on the CD that accompanies this book. On the CD, see \WORKSHOP\DATABASE\TDC\REFERENCE\FILTER.HTM. To get to the online version, visit the MSDN Online Resource page at msdn.microsoft.com/resources/schurmandhtml.htm, or open the file MSDN_OL.htm on the companion CD, and then choose Filter Property.

click to view at full size.

Figure 20-5. The same set of records after being sorted and filtered.

Adding, Changing, and Deleting Data

Some DSOs allow the user to modify a recordset by changing a field and by adding or deleting data from the active recordset in memory. The TDC is one such DSO (although it does not allow changes to be made to the source data file). The syntax for the AddNew method is as follows:

 dsoID.recordset.AddNew() 

Once the AddNew method is used, a new, empty record is added to the end of the recordset. The empty fields can be filled through script or through an HTML element that supports recordset updating. (See Table 20-1 on page 349.) The syntax for changing a field is as follows:

 dsoID.recordset.fields(`column name')="new value" 

We could have applied these techniques to the previous code listings as follows:

 herbRS.AddNew() herbRS.fields(`common')="Dhaction" herbRS.fields(`botan')="Dynamicia HTMLicus in Actionious" herbRS.fields(`usage')="Creating Cool Web Pages" 

The Delete method works in a similar fashion, using this syntax:

 dsoID.recordset.Delete() 

This technique deletes the active record from the recordset. Adding and changing a recordset is demonstrated in Code Listing 20-6.

Although the TDC does not support changing data on the remote source, other DSOs—for instance RDS—do include this feature. Information about RDS and other DSOs can be found on the SBN Workshop Web site and on the CD that accompanies this book. On the CD, see DHTML, HTML, & CSS/Data Binding/Adding a Data Source Object to a Page. To get to the online version, visit the MSDN Online Resource page at msdn.microsoft.com/resources/schurmandhtml.htm, or open the file named MSDN_OL.htm on the companion CD, and then choose Adding a DSO. As stated earlier, the Microsoft Universal Data Access site (microsoft.com/data) also provides useful technical information and further references about DSOs and data access in general.

Data Events

A number of tools are available for controlling and interacting with data bound elements on a page. Data bound elements are HTML elements that have been linked to a DSO that contains data. Using standard Object Model events, content developers can write scripts that will react to changes in data or data bound elements.

Dynamic HTML Data Binding Events

Internet Explorer supports many data binding events, some of which apply to the DSO, others that apply to the data bound elements, and one that applies only to the window object. The following list describes the most common data binding events:

Data Binding Event Event Object
onbeforeupdate Data bound element
onafterupdate Data bound element
onerrorupdate Data bound element
onbeforeunload window object
onrowenter DSO
onrowexit DSO
ondataavailable DSO
ondatasetcomplete DSO
ondatasetchanged DSO
onreadystatechange DSO

The script code in Code Listing 20-6 uses both the ondatasetcomplete and ondatasetchanged events. The ondatasetcomplete event is fired when the data is fully loaded. It can be used to ensure that no attempts are made to access content that has not yet loaded. The ondatasetchanged event is fired whenever there is a change in the way the working set of data is sorted or filtered. Note that each of these events is fired both when the page is loaded and every time a new sort operation is performed.

Code Listing 20-6.

 <HTML> <HEAD> <TITLE>Code Listing 20-6</TITLE> <OBJECT ID="herbTDC" CLASSID="CLSID:333C7BC4-460F-11D0-BC04-0080C7055A83">   <PARAM NAME="TextQualifier" VALUE="!">   <PARAM NAME="FieldDelim" VALUE="|">   <PARAM NAME="DataURL" VALUE="herbs.txt">   <PARAM NAME="UseHeader" VALUE="true"> </OBJECT> <SCRIPT LANGUAGE="JavaScript" FOR="window" EVENT="onload">   herbRS=herbTDC.recordset;   herbRS.MoveFirst() </SCRIPT> <SCRIPT LANGUAGE="JavaScript" FOR="herbTDC" EVENT="ondatasetcomplete">   alert("The data is fully loaded.") </SCRIPT> <SCRIPT LANGUAGE="JavaScript" FOR="herbTDC" EVENT="ondatasetchanged">   alert("The working data set has changed.") </SCRIPT> </HEAD> <BODY> <INPUT TYPE="button" VALUE="Add Record"   onclick="herbRS.AddNew();            herbRS.fields(`common')=`Dhaction';            herbRS.fields(`botan')=`Dynamicia HTMLicus in Actionious';            herbRS.fields(`usage')=`Creating Cool Web Pages'"> <B>Sort by:</B> <SELECT onchange="herbTDC.Sort=(`+'+this.value); herbTDC.Reset()">   <OPTION VALUE="">None</OPTION>   <OPTION VALUE="common">Common Name</OPTION>   <OPTION VALUE="botan">Botanical Name</OPTION>   <OPTION VALUE="usage">Usage</OPTION> </SELECT> <TABLE DATASRC="#herbTDC">    <THEAD STYLE="font-weight: bold">     <TR><TD>Common Name</TD><TD>Botanical Name</TD><TD>Usage</TD></TR>   </THEAD>     <TR>       <TD><SPAN DATAFLD="common"></SPAN></TD>       <TD><SPAN DATAFLD="botan"></SPAN></TD>       <TD><SPAN DATAFLD="usage"></SPAN></TD>     </TR> </TABLE> </BODY> </HTML> 



Dynamic HTML in Action
Dynamic HTML in Action
ISBN: 0735605637
EAN: 2147483647
Year: 1999
Pages: 128

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net