Scrollable Area : the HTC option

Just for info I give back the HTC code (only for IE) originally written by the Microsoft Web Team, and I am sure it's possible to adapt this code to work with other browsers.

Update: I used this with Datagrid and yes it's working well (tested with IE 6)

<asp:datagrid id="myDG" runat="Server" bodyHeight="100" bodyCSS="tblBody" headerCSS="tblHeader" cssclass="tblMain_silver" AutoGenerateColumns="false" Font-Size="8" HeaderStyle-Font-Bold="True" HeaderStyle-HorizontalAlign="Center" Width="830">

 

If the Web Team had a dollar for every time we've seen an e-mail from a developer asking for this feature we wouldn't be pining for the good old days when the NASDAQ was sky high. Well, it's high time we addressed this request and satisfy our loyal readers. Naturally, we thought the best way to do this was to come up with an HTML Behavior that we could attach to any table we want, even ones emitted by the ASP.NET DataGrid. Our control, ScrollTable.htc, is yours to customize or improve. We'll explain how it works.

First, the scrolltable.htc is attached to our table element by specifying the behavior attribute in the CSS class used on the element.

   behavior:url(scrolltable.htc);

When the ondocumentready event fires, our behavior creates two table elements by calling cloneNode(false) on our table. We clone the table without child elements rather than creating new tables so that we preserve attributes, such as cellSpacing and style, instead of manually having to add each attribute to our two new tables. The two table elements we create are the header containing the first row of the table in the test page and the body containing all of the other rows. The body table is inserted into a container DIV with the CSS overflow attribute set to auto, which allows scrolling if necessary. The table in the test page is then modified to contain only two rows. The first row contains a TD and the header table, and the second row contains a TD with the container DIV. Next, we store the offsetWidths of all the cells in the first row of the table in an array, rgWidths, so that we can set the cells in the header and body tables and they remain in sync. Then we add the header row to the tblHeader element and the body rows to the tblBody element. We then insert the tblBody into the container DIV. After that, we remove all the rows from our table and insert two new rows—one for the tblHeader and one for tblBody. Once all the rows are added to the body and header tables, we set the width of the columns in the two tables to the width values stored in our array. Finally, we set some properties on the header and body to make them look right.

In TestPage.htm, one can see that we have added three expando properties to our TABLE. The first attribute, bodyHeight, is used to set the height of the body. If this property is not set, the body will not scroll. We also have headerCSS and bodyCSS, which simply allow you to specify separate CSS classes for the header and body tables.

Here are the sources:

ScrollTable.htc

<PUBLIC:ATTACH event="ondocumentready" handler="onDocumentReady" />
<SCRIPT language="JScript">
function onDocumentReady()
{
   // Create elements
   var tblHeader = this.cloneNode(false);
   var tblBody   = this.cloneNode(false);
   var divCntr   = document.createElement("DIV");

   // Get column widths
   var rgWidths = new Array();
   for (var i = 0; i < this.rows[0].cells.length; i++)
   {
      rgWidths[i] = this.rows[0].cells[i].offsetWidth;
   }

   // Add header row
   var tbdyHeader = document.createElement("TBODY");
   tblHeader.appendChild(tbdyHeader);
   tbdyHeader.appendChild(this.rows[0].cloneNode(true));

   // Add body rows
   var tbdyBody = document.createElement("TBODY");
   tblBody.appendChild(tbdyBody);
   
   for (var i = 1; i < this.rows.length; i++)
   {
      var oRow = this.rows[i].cloneNode(true);
      tbdyBody.appendChild(oRow);
   }

   // Set up body container
   divCntr.style.overflow = "auto";
   if (this.bodyHeight) divCntr.style.height = this.bodyHeight;
   divCntr.appendChild(tblBody);

   // Change existing table
   for (var i = this.rows.length; i > 0; i--)
   {
      this.rows[i-1].removeNode(true);
   }
   var tr1 = this.insertRow();
   var td1 = tr1.insertCell();
   var tr2 = this.insertRow();
   var td2 = tr2.insertCell();
   
   td1.appendChild(tblHeader);
   td2.appendChild(divCntr);

   // Set column widths of all but the last column
   for (var i = 0; i < rgWidths.length - 1; i++)
   {
      tblHeader.rows[0].cells[i].width = rgWidths[i];   
      tblBody.rows[0].cells[i].width   = rgWidths[i];
   }

   tblHeader.style.fontSize    = "100%";
   tblHeader.width             = "100%";
   tblHeader.style.tableLayout = "fixed";
   tblHeader.className         = this.headerCSS ? this.headerCSS : "";
   tblHeader.border = 0;

   tblBody.style.fontSize      = "100%";
   tblBody.width               = "100%";
   tblBody.style.tableLayout   = "fixed";
   tblBody.className           = this.bodyCSS ? this.bodyCSS : "";
   tblBody.border = 0;

   this.cellSpacing = 0;
   this.cellPadding = 0;
}
</SCRIPT>

TestPage.htm

<HTML>
<HEAD>
<STYLE>
.tblMain
{
   behavior:url(scrolltable.htc);
   background-color: highlight;
   border: 1px solid darkblue;
   font-family: Verdana;
   font-size: .8em;
}
.tblHeader
{
   color: highlighttext;
}
.tblBody
{
   background-color: #EEEEEE;
   color: darkblue;
}
</STYLE>
</HEAD>
<BODY>
<TABLE bodyHeight="100" bodyCSS="tblBody" headerCSS="tblHeader" 
   class="tblMain" width="75%" cellspacing=5 cellpadding=0>
<TR>
   <TD nowrap>Header A</TD>
   <TD nowrap>Header B</TD>
   <TD nowrap>Header C</TD>
</TR>
<TR>
   <TD>Aaaaaaaaaaaaaaaaaaa</TD><TD>B</TD><TD>Ccccccccccccccccccc</TD>
</TR>
<TR>
   <TD>A</TD><TD>Bbbbbbb</TD><TD>C</TD>
</TR>
<TR>
   <TD>A</TD><TD>B</TD><TD>C</TD>
</TR>
<TR>
   <TD>A</TD><TD>B</TD><TD>C</TD>
</TR>
<TR>
   <TD>A</TD><TD>B</TD><TD>C</TD>
</TR>
<TR>
   <TD>A</TD><TD>B</TD><TD>C</TD>
</TR>
<TR>
   <TD>A</TD><TD>B</TD><TD>C</TD>
</TR>
<TR>
   <TD>A</TD><TD>B</TD><TD>C</TD>
</TR>
<TR>
   <TD>A</TD><TD>B</TD><TD>C</TD>
</TR>
</TABLE>
</BODY>
</HTML>

4 Comments

  • It's not really possible to adapt this code because behaviors are only supported by IE 5.0 or better.

  • Yes but I was more thinking about the Javascript code inside the HTC file. This should be a starting point

  • This works great for me .... but, for example I have a table with 41 lines (23 are shown without scrolling down), when I print it only prints the first 23. I've tried changing the code slightly and have 2 CSS's 1 for screen and 1 for print. The print CSS ignores the Scrolltable.htc and the Bodyheight is hardcoded in the js. which resides in my screen CSS. But no use .... still prints what you see.



    Anyway ideas would be greatly appreciated!

  • I tested your solution and I got errors when the table had been set with absolutely position...

Comments have been disabled for this content.