Home Articles FAQs XREF Games Software Instant Books BBS About FOLDOC RFCs Feedback Sitemap
irt.Org

Related items

How to do the impossible with Google Gears

Out and About

JavaScript Bouncing Balls

Multi-dialogue forms on one page

Drag and Drop with Microsoft Internet Explorer 5

Dynamic Floating Tool Tips

What is DHTML?

Image Manipulation Techniques

String Gradients the Fun Way!

"The Light Fantastic"

Turning Tables Into Selection Lists

You are here: irt.org | Articles | Dynamic HTML (DHTML) | Turning Tables Into Selection Lists [ previous next ]

Published on: Monday 13th March 2000 By: Abby Beifeld

Introduction

While HTML list boxes are fine for providing a user with a simple list of options, they tend to fall short when you find yourself needing to display multiple columns of information in your selection lists.

This article will describe techniques that you can use to create a multiple column selection list that looks much like the selection lists that you would find in a typical desktop application. It combines tables, frames, JavaScript and Dynamic HTML to provide you with this appearance and it works in MSIE4+ as well as Netscape Communicator 4.

The Basic Functionality

The basic functionality is really quite simple and, if you're a long time reader of irt.org, probably all components that you already know. It's when you start to take all of these different components and use them together that things start to get interesting.

Lets start off by looking at the basic components.

Step 1: Creating the Window

Create a window with two frames. The top frame will contain the list column headers; the bottom will contain the list itself. By separating our headers from the list, we prevent the annoying behavior of having our headers scroll out of view as the user scrolls through the list.

Placing your list into a frame will also bring about other benefits. For one, you can place a third frame into this main window that displays details about items as the user selects them. These details remain in view on the screen, even as the user scrolls through your list. Another benefit of using frames is that it allows you to specify marginWidth and marginHeight for your list window, values that you need to be aware of when handling row highlighting in Netscape. For now, simply set marginWidth and marginHeight to 0 on each frame.

<html><head>
<frameset border="0" rows="20, *">
<frame name="header" src="header.htm" 
       marginWidth=0 marginHeight=0 scrolling="no" noResize >
<frame name="list" src="list.htm"
       marginWidth=0 marginHeight=0 noResize>
</frameset>
</head></html>

Step 2: Creating the Column Headers

In your header frame, create an HTML table that defines both a table width and the width for each of the individual columns. This will allow proper alignment of your headers with your list columns.

<table width=400 cellspacing=0 cellpadding=0 border=0>
<tr align="left">
    <td width=50><b>ID</b></td>
    <td width=250><b>Name<<b>/td>
    <td width=100><b>Phone #<b></td></tr>
</table>

Note: I am using TD with B tags for my column headers here rather than TH because TH was causing things to line up funny in MSIE for Macintosh.


Step 3: Creating the List

The list frame will display your selection list inside of a formatted HTML table. Here, we want to create each data item inside of the table as a hyper link so that the user can select a row by clicking on any of that row's items. For now, point your hyper links point to a blank JavaScript function named SelectRow( ). We will fill in the details later on.

In addition, we add a few features that will allow us to highlight our selected rows. The first is to give each row a unique ID. To keep our example simple, these IDs will correspond to the line number for each row, starting from 0. These row IDs are used in two places:

  1. Each data item's hyper link will pass this row ID as its argument to SelectRow( ). This will allow us to identify which row has been selected by the user.
  2. Each table row (TR) is given an ID with the name "row" + rowNumber (i.e., "row1"). This will allow us to highlight selected rows in MSIE.

To facilitate row highlighting in Netscape, we also put the entire list table inside of a LAYER tag with its z-index set to 1.

<layer z-index=1>
<table width=400 cellspacing=0 cellpadding=0 border=0>
<tr id="row0">
    <td width=50> <a href="JavaScript:SelectRow( 0 )">0</a></td>
    <td width=250><a href="JavaScript:SelectRow( 0 )">Carol Cunnings</a></td>
    <td width=100><a href="JavaScript:SelectRow( 0 )">555-7890</a></td></tr>
<tr id="row1">
    <td width=50> <a href="JavaScript:SelectRow( 1 )">1</a></td>
    <td width=250><a href="JavaScript:SelectRow( 1 )">Jane Doe</a></td>
    <td width=100><a href="JavaScript:SelectRow( 1 )">555-1234</a></td></tr>
<tr id="row2">
    <td width=50> <a href="JavaScript:SelectRow( 2 )">2</a></td>
    <td width=250><a href="JavaScript:SelectRow( 2 )">Joe Shmoe</a></td>
    <td width=100><a href="JavaScript:SelectRow( 2 )">555-1212</a></td></tr>
<tr id="row3">
    <td width=50> <a href="JavaScript:SelectRow( 3 )">3</a></td>
    <td width=250><a href="JavaScript:SelectRow( 3 )">Bill Williams</a></td>
    <td width=100><a href="JavaScript:SelectRow( 3 )">555-7890</a></td></tr>
</table>
</layer>

Finally, we create our JavaScript function which takes a single argument, the selected row ID.

<script language="JavaScript"><!--
function SelectRow( rowID ){}
//--></script>

This will give you a pretty basic table with row selection:

ID Name Phone #
0 Carol Cunnings 555-7890
1 Jane Doe 555-1234
2 Joe Shmoe 555-1212
3 Bill Williams 555-7890

Of course, we could stop here but then we haven't accomplished anything new. At a minimum, we want to provide a visual indication of the row that was selected. This can be done by highlighting the selected row, as described in the following section.

Step 4: Highlighting Selections

Row highlighting is handled differently for MSIE and Netscape. However, by making a few modifications to our code, we can still maintain readability.

Two basic functions are needed for showing row selection. The first is to highlight rows as they are selected. The second is to unhighlight rows as they become unselected. For the purposes of this example, a single selection list is used. That is, when the user clicks on a row, that row becomes the only selected row. We use the global variable selectedRow to keep track of the currently selected row.

Therefore, we will modify our SelectRow( ) method to call the functions for handling these 2 tasks and to keep track of the currently selected row.

<SCRIPT LANGUAGE="JavaScript"><!--
// keep track of line # for currently selected row
var selectedRow = "undefined";  

function SelectRow( rowID )
{
    // unhighlight the previously selected row, if any
    if( selectedRow != "undefined" )
        UnHighlightRow( selectedRow );

    // if necessary, convert row ID to row line number here
    rowNumber = rowID;

    // highlight and save selected row
    HighlightRow( rowNumber );
    selectedRow = rowNumber;
}
//--></SCRIPT>

To insure that functionality is matched with browser type, we will create browser-dependant functions and then point HighlightRow() and UnHighlightRow( ) to the correct function, based on the browser type.

<script language="JavaScript"><!--
function MSIEHighlightRow( rowNumber ){}
function MSIEUnHighlightRow( rowNumber ){}
function NetscapeHighlightRow( rowNumber ){}
function NetscapeUnHighlightRow( rowNumber ){}

// set functions according to browser type
if( navigator.appName.search(  /Microsoft Internet Explorer/i ) > -1 )
{
    HighlightRow = MSIEHighlightRow;
    UnHighlightRow = MSIEUnHighlightRow;
}
else
{
    // else assume Netscape (a real application should do more complete checking!)
    HighlightRow = NetscapeHighlightRow;
    UnHighlightRow = NetscapeUnHighlightRow;
}
//--></script>

Now to fill in the details:

Highlighting in MSIE

Highlighting a row in MSIE is a simple matter of finding the row that was selected and changing its background color. We find the selected row based upon the row (TR) IDs that we specified in our list table and the rowID argument that we pass to SelectRow( ) from our data item hyper links. Note that this code assumes that we have named our table's row IDs according to the format of "row" + rowID (i.e., "row1") when we created the list.

To show selection, we set the selected row's background to some color (lightsteelblue is used here) which causes the row to appear highlighted. To show that an item has been unselected, we set its background color to the web page's background color (white is assumed here).

<script language="JavaScript"><!--
function MSIEUnHighlightRow( rowNumber )
{
    var targetRow = eval( "document.all.row" + rowNumber );
    targetRow.bgColor = "white";
}
function MSIEHighlightRow( rowNumber )
{
    var targetRow = eval( "document.all.row" + rowNumber );
    targetRow.bgColor = "lightsteelblue";
}
//--></script>

Highlighting in Netscape

Since Netscape does not support changing the background color of table rows on the fly, we instead use Netscape's movable layers to show row selection. This is done by creating an "empty" layer with a background color set to our highlight color. This layer is then moved into position behind the selected row, thus giving that row the appearance of being highlighted.

To do this, create a layer that is the same height as our list rows by placing a single "empty" column in the table (you should actually use &nbsp; -- the non-breaking space character) and set it's cellspacing and cellpadding to 0. For the table width, you can either use the width of your list table or use 100%. Using 100% creates a highlight bar that goes across the entire width of the frame -- I think this looks a little nicer, but you can play with both methods to see which you prefer.

Next, give the layer a z-index of 0 to insure that this layer always sits underneath of our table. Also, set the background color (bgcolor) for this layer to the color that you wish to use for highlighting rows. Finally, set this layer to be initially hidden (visibility="hidden")

<layer id='highlightLayer' bgcolor='lightsteelblue' z-index=0 visibility='hide'>
<table width=100% cellspacing=0 cellpadding=0 border=0>
       <tr><td>&nbsp;</td></tr>
</table></layer>

For Netscape, the UnHighlightRow( ) function simply sets highlight layer to invisible.

Our HighlightRow() function is responsible for setting the layer to visible and positioning it behind the selected row. In order to position the highlight layer correctly, we need to determine the x,y coordinates of the selected row. The first consideration here is the offset provided by margin width and margin height on the list window. Since we have placed the list in a frame with both margin width and height set to 0, we have no offset to worry about in this example. When marginWidth is 0, the x position will always be set to 1 (note that 0 would seem more intuitive, but Netscape pushes the list out by 1 pixel, making an x coordinate of 1 more accurate).

The height of your rows is going to be font dependent. However, our highlight layer will tell us what this height is, since it too consists of a single table row. You can get the layer's height by using its clip.height attribute. Then, as long as your row numbers starts at 0, you can calculate your highlight layer's y position with: row number * layer.clip.height.

<script language="JavaScript"><!--
function NetscapeHighlightRow( rowNumber )
{
    var highlight = document.layers["highlightLayer"];
    var height = highlight.clip.height;
    highlight.moveTo( 1, ( rowNumber * height ) );
    highlight.visibility="show";
}
function NetscapeUnHighlightRow( rowNumber )
{
    var highlight = document.layers["highlightLayer"];
    highlight.visibility="hide";
}
//--></script>

Select Initial Row

Now that your functions are in place, you may want to add a call to SelectRow( 0 ) inside of your BODY onLoad method. This will give your user a default selection when they first load the page. By showing the users what a selected item looks like, you provide them with a hint for how the list works.

Step 5: Displaying the Details

You can now create that third frame in your window to display details about the selected item. You have several options for doing this, including:

  1. Load a new page into the details frame each time a new item is selected.
  2. Load an HTML form into your details frame and fill in the values for the form elements, on the fly, based upon the selected item.
  3. Use Dynamic HTML to write out the details to this third frame on the fly.

Option #1 can be handled by placing the following code into your SelectRow( ) function, after the row has been highlighted and saved:

<script language="JavaScript"><!--
function SelectRow( rowID )
{
    [...]
    var pageToLoad = "page" + rowID + ".htm";
    parent.details.document.location = pageToLoad;
}
//--></script>

For the last two options, you will probably find it easiest to keep your list data inside of an array of objects, where the array index corresponds to the row ID in your list. You can view an example of Option #2 which uses the object array technique along with some other techniques suggested in the next section.

Option #2 can fill in the HTML form elements with the following code, placed into SelectRow( ):

<script language="JavaScript"><!--
// fill in the HTML fields in the detailsForm
// from the people array (indexed by rowID)
var dtlsForm = parent.details.document.detailsForm;
dtlsForm.personID.value = people[rowID].id;
dtlsForm.personName.value = people[rowID].name;
dtlsForm.phone.value = people[rowID].phone;
dtlsForm.description.value = people[rowID].description;
//--></script>

Option #3 would entail writing out the HTML to be displayed in the details frame, from scratch, each time a new item is selected. For example, you could have your SelectRow( ) method add the following code to do this:

<script language="JavaScript"><!--
// Write out the details frame
// using people array (indexed by rowID )
var target = parent.details.document;
target.open( );
target.writeln( "<html><head></head>" );
target.writeln( "<body>" );
target.writeln( "<center><h1>" + people[rowID].name + "</h1></center>" );
target.writeln( "ID #:" + people[rowID].id + "<br>" );
target.writeln( "Phone #:" + people[rowID].phone );
target.writeln( "</body></html>" );
target.close( );
//--></script>

Fancying It Up

Now that you have the basics down, there are several things that you can do to fancy this page up. I'm not much of a graphic designer, but here are a few ideas to get you started.

Hiding Underlining

One thing that I prefer doing is hiding the underlining of each data item and keeping each data item's color consistent (rather than having the link color change after an item has been clicked). Removing the underlining and keeping the color consistent makes the list look more like one that a user might find in one of their desktop applications and makes the application look cleaner.

This can be easily handled with style sheets by placing the following style sheet rule in the HEAD of your list window:

<style><!--
A { text-decoration: none; color: blue; }
--></style>

Providing Row Descriptions

Another idea is to use the onMouseOver attribute in your data item's hyper links to display a description for the item in the web browser's status bar.

<a href="JavaScript:SelectRow( 0 )" 
   onMouseOver="status='This is row 0'; return true;">

If you keep an array of your objects, indexed by row ID, than you can make this easier by calling a DisplayDescription( ) method:

<a href="JavaScript:SelectRow( 0 )" 
   onMouseOver=return DisplayDescription( 0 );

<SCRIPT LANGUAGE="JavaScript"><!--
function DisplayDescription( rowID )
{
    window.status = objArray[rowID].description;
    return true;
}
//--></SCRIPT>

More Ideas

I'm sure that you can find many more ideas by searching through irt.org's collection of JavaScript Articles. A couple that look particularly interesting for our list are:

Finally, on a note of code-fanciness... I have simplified the examples at the expense of having some silliness in my code. The example below uses both an array of objects (where each object instance represents an item in the list) and also writes out the list table -- with those same exact items -- by hand. A saner programmer might decide to simply loop through this array of objects to generate the HTML for the list table itself. ;-)

Example

This example combines all of the components described in this article, save those suggestions given in the More Ideas section.

The individual files for the example are:

Related items

How to do the impossible with Google Gears

Out and About

JavaScript Bouncing Balls

Multi-dialogue forms on one page

Drag and Drop with Microsoft Internet Explorer 5

Dynamic Floating Tool Tips

What is DHTML?

Image Manipulation Techniques

String Gradients the Fun Way!

"The Light Fantastic"

©2018 Martin Webb