5.8. Dynamic Tables
The IE and W3C DOMs have identical
convenience facilities for dynamically creating and modifying table
structures (unfortunately, they are broken in IE 5/Mac). Once you
have a reference to the table or
tbody element object, the rest is the same across
DOMs until you get to populating the td elements
with content (as discussed in the previous section). This facility
makes it possible, for example, to let client-side scripts sort the
table on each column in response to user request—no need to go
back to the server.
The regularity of tables and the design behind the table row and cell
construction methods permit very compact and tight loops to generate
a lot of a document's tree. Essentially the process
is:
-
Insert an empty
tr element at the desired position in the table.
-
Insert empty td elements into the new
tr element object.
-
Populate the td
elements with content.
Sources for your table data can be
JavaScript arrays (arrays of objects are particularly useful) or, in
more recent browsers, external XML documents loaded into virtual
documents. This discussion doesn't cover the
Microsoft proprietary data binding capabilities, which are available
in IE for Windows and, with some limitations, for the Mac. Read more
about data binding under the dataFld property of
all objects in Chapter 9.
Example 5-11 is a code listing for a simple
application that uses an array of objects embedded within the
document as a data source.
Example 5-11. Dynamic table
<html>
<head>
<title>Dynamic Table</title>
<style type="text/css">
body {background-color:#ffffff}
table {table-collapse:collapse; border-spacing:0}
td {border:2px groove black; padding:7px}
th {border:2px groove black; padding:7px}
.ctr {text-align:center}
</style>
<script language="JavaScript" type="text/javascript">
// Table data -- an array of objects
var jsData = new Array( );
jsData[0] = {bowl:"I", year:1967, winner:"Packers", winScore:35,
loser:"Chiefs", losScore:10};
jsData[1] = {bowl:"II", year:1968, winner:"Packers", winScore:33,
loser:"Raiders (Oakland)", losScore:14};
jsData[2] = {bowl:"III", year:1969, winner:"Jets", winScore:16,
loser:"Colts (Balto)", losScore:7};
jsData[3] = {bowl:"IV", year:1970, winner:"Chiefs", winScore:23,
loser:"Vikings", losScore:7};
jsData[4] = {bowl:"V", year:1971, winner:"Colts (Balto)", winScore:16,
loser:"Cowboys", losScore:13};
// Sorting functions (invoked by sortTable( ))
function sortByYear(a, b) {
return a.year - b.year;
}
function sortByWinScore(a, b) {
return b.winScore - a.winScore;
}
function sortByLosScore(a, b) {
return b.losScore - a.losScore;
}
function sortByWinner(a, b) {
a = a.winner.toLowerCase( );
b = b.winner.toLowerCase( );
return ((a < b) ? -1 : ((a > b) ? 1 : 0));
}
function sortByLoser(a, b) {
a = a.loser.toLowerCase( );
b = b.loser.toLowerCase( );
return ((a < b) ? -1 : ((a > b) ? 1 : 0));
}
// Sorting function dispatcher (invoked by table column links)
function sortTable(link) {
switch (link.firstChild.nodeValue) {
case "Year" :
jsData.sort(sortByYear);
break;
case "Winner" :
jsData.sort(sortByWinner);
break;
case "Loser" :
jsData.sort(sortByLoser);
break;
case "Win" :
jsData.sort(sortByWinScore);
break;
case "Lose" :
jsData.sort(sortByLosScore);
break;
}
drawTable("bowlData");
}
// Remove existing table rows
function clearTable(tbody) {
while (tbody.rows.length > 0) {
tbody.deleteRow(0);
}
}
// Draw table from 'jsData' array of objects
function drawTable(tbody) {
var tr, td;
tbody = document.getElementById(tbody);
// remove existing rows, if any
clearTable(tbody);
// loop through data source
for (var i = 0; i < jsData.length; i++) {
tr = tbody.insertRow(tbody.rows.length);
td = tr.insertCell(tr.cells.length);
td.setAttribute("class", "ctr");
td.innerHTML = jsData[i].bowl;
td = tr.insertCell(tr.cells.length);
td.innerHTML = jsData[i].year;
td = tr.insertCell(tr.cells.length);
td.innerHTML = jsData[i].winner;
td = tr.insertCell(tr.cells.length);
td.innerHTML = jsData[i].loser;
td = tr.insertCell(tr.cells.length);
td.setAttribute("class", "ctr");
td.innerHTML = jsData[i].winScore + " - " + jsData[i].losScore;
}
}
</script>
</head>
<body onload="drawTable('bowlData')">
<h1>Super Bowl Games</h1>
<hr>
<table id="bowlGames">
<thead>
<tr><th>Bowl</th>
<th><a href="#" title="Sort by Year"
onclick="sortTable(this)">Year</a></th>
<th><a href="#" title="Sort by Winning Team"
onclick="sortTable(this)">Winner</a></th>
<th><a href="#" title="Sort by Losing Team"
onclick="sortTable(this)">Loser</a></th>
<th>Score <a href="#" title="Sort by Winning Score"
onclick="sortTable(this)">Win</a> - <a href="#"
title="Sort by Losing Score" onclick="sortTable(this)">Lose</a></th>
</tr>
</thead>
<tbody id="bowlData"></tbody>
</table>
</body>
</html>
Figure 5-2 shows the table as rendered by
JavaScript from the embedded data. The function that generates the
table also redraws the table when the data is sorted and redisplayed.
Figure 5-2. A dynamically sortable table rendered from embedded JavaScript data
Notice in Example 5-11
that the HTML portion simply provides a tbody
placeholder for the dynamic table data. A tbody
element object has the same insertRow( ) method
available to it as the table element object (and
the thead and tfoot, for that
matter). While it's true that a separate function
could be used for simply replacing the content of
td elements after the first table is created, the
process in this example (i.e., removing rows and making new ones for
each redrawing) allows one function to handle both the initial and
subsequent table drawing. The drawTable( )
function uses a hybrid of formal W3C DOM terminology (the
setAttribute( ) method, for instance) and the
convenience of the IE innerHTML property. The
purpose of this mixture is to demonstrate how the two models can work
together when supported by your target browsers (IE 5 and later for
Windows and Netscape 6 in this case).
 |  |  | | 5.7. Changing Content |  | 5.9. Client-Side Includes |
Copyright © 2003 O'Reilly & Associates. All rights reserved.
|
|