Dynamic HTML: The Definitive Reference, 2rd Ed.Dynamic HTML: The Definitive ReferenceSearch this book

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:

  1. Insert an empty tr element at the desired position in the table.

  2. Insert empty td elements into the new tr element object.

  3. 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

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).



Library Navigation Links

Copyright © 2003 O'Reilly & Associates. All rights reserved.