Collections of web application techniques

Tuesday, August 11, 2009

How to Create HTML Scrollable Data Table

This blog describes how you can create a scrollable data table for your web applications. The scrollable table allows user to scroll vertically to see all the rows while maintaining the column headers and footers in fixed positions.

Below is an example of the output table:



Setting up this kind of table is fairly simple. The main thing you have to do is to specify the width of each column and make sure that the header and the data column have the same width. The scrollable table above actually consists of three different tables: the first one is for the table caption and column headers, the second one is for all the data row, and the last one is for the footer.

For the table above, I defined these styles:


.col1 {width:6.0em; vertical-align:top; padding:2px;}
.col2 {width:6.0em; vertical-align:top; padding:2px;}
.col3 {width:15.0em; vertical-align:top; padding:2px;}
.col4 {width:6.0em; vertical-align:top; padding:2px;}
.col5 {width:6.0em; vertical-align:top; padding:2px;}
.col6 {width:6.0em; vertical-align:top; padding:2px;}
.col7 {width:6.0em; vertical-align:top; padding:2px;}
.col8 {width:6.0em; vertical-align:top; padding:2px;}


The total width is then 57.0em. But to make things look good on IE 7 and FireFox 3, I bump it up to 60.5em and wrap each table in a div tag.

Header:

Note the width and the overflow in the div tag.


<div style="border: 1px solid #CCCCCC; width:60.5em; overflow:none; margin-top:5px; padding:0;">
<table style="background:#FFFFFF; margin:0; padding:0;" cellpadding="0" cellspacing="1" summary="Header layout for data">
<caption style="padding: 4px;font-weight:bold">
Assigned Stations Statistics
</caption>
<th scope="col" class="col1" style="background: url(../fpps-toolbar/images/toolbarbg.png);">
<h:outputLink onclick="setSelected(true); return false;">All</h:outputLink>
<span style="padding-left:2px; padding-right:4px">/</span>
<h:outputLink onclick="setSelected(false); return false;">None</h:outputLink>
</th>
<th scope="col" class="col2">Station</th>
<th scope="col" class="col3">Role(s)</th>
<th scope="col" class="col4">Assigned</th>
<th scope="col" class="col5">Awaiting</th>
<th scope="col" class="col6">In Process</th>
<th scope="col" class="col7">Rejected</th>
<th scope="col" class="col8">Error</th>
</table>
</div>


Data:
Although the data table below is rendered using the Java Server Faces tag which might not make sense if you are not familiar but the important things to note are:
  • the table is wrapped in a div that allows vertical scrolling only via the overflow-y
  • the with is 62em to account for the vertical scrollbar
  • the style classes for each of the column (columnClasses attribute) are exactly the same as the header column.


    <div style="border: 1px solid #CCCCCC; height:20em; width:62em; overflow-y:scroll; background: #FFFFFF; margin:0; padding:0;">
    <h:dataTable id="homeStatTable"
    var="data"
    rowClasses="rowOdd,rowEven"
    cellpadding="0"
    cellspacing="1"
    columnClasses="col1 center,col2 center,col3,col4 right,col5 right,col6 right,col7 right,col8 right"
    footerClass="footer"
    value="#{homePageUserData.userFacilities.values.toArray()}">
    <h:column>
    <h:selectBooleanCheckbox id="active" value="#{data.active}"/>
    <f:facet name="footer"></f:facet>
    </h:column>
    <h:column>
    #{data.code}
    </h:column>
    <h:column>
    CLERK
    </h:column>
    <h:column>
    #{data.assigned}
    </h:column>
    <h:column>
    #{data.awaiting}
    </h:column>
    <h:column>
    #{data.inProcess}
    </h:column>
    <h:column>
    #{data.rejected}
    </h:column>
    <h:column>
    #{data.error}
    </h:column>
    </h:dataTable>
    </div>


    Footer:
    The footer is similar to the header which is also wrapped in the same div style with the overflow as none. Again each of the footer column has the same style as its corresponding header and data columns.


    <div style="border: 1px solid #CCCCCC; width:60.5em; overflow:none; margin:0; padding:0;">
    <table style="background:#FFFFFF; margin:0; padding:0;" cellpadding="0" cellspacing="1" summary="Layout for summary data">
    <th scope="col" class="col1"></th>
    <th scope="col" class="col2"></th>
    <th scope="row" class="col3 right" style="text-align:right">Total:</th>
    <th scope="col" class="col4 right">#{homePageUserData.claimsAssigned}</th>
    <th scope="col" class="col5 right">#{homePageUserData.claimsAwaiting}</th>
    <th scope="col" class="col6 right">#{homePageUserData.claimsInProcess}</th>
    <th scope="col" class="col7 right">#{homePageUserData.claimsRejected}</th>
    <th scope="col" class="col8 right">#{homePageUserData.claimsError}</th>
    </table>
    </div>