4umi.com/web/javascript/tablesum.php

Sum-a-column

Table Javascript

Often the content of cells in a table needs to be manipulated based on the content of other cells. When tables are used for spreadsheet-like purposes, which they were invented for, modern browsers may bring not only the presentation, but also their functionality to the client side.

A simple table

Below is a silly, little table with one purpose only: to demonstrate how each cell in the last row can display the total numerical value of the text of the cells in each column. Still there?

The table has a straightforward markup: an id="sumtable" as its only inline attribute, and a <tbody> element as its only child. Inside are four <tr> elements, the last one attributed with class="total" to attach a css rule that makes its text bold. The rows contains only cells. No surprise as they are the only possible childnodes, but the number of cells varies across the rows, which not all browsers handle in quite the same way. There are no colspans or rowspans set.

The cells contain our data. As the script reads the nodeValue of the cell's firstChild, expecting the number to add to the total for that column, other markup in the cell is not possible. If the text is nothing numerical, a value of 0 (zero) is assumed, as the example demonstrates. The cells in the last row, where the script will write its results, are filled with dummy textnodes, the question marks in the example, placeholders to ensure that accessing their firstChild property will actually return a node. A space is ignored by some browsers (notably ie), but the non-breaking space &nbsp; ( ) or &hellip; (…) could also be used appropriately.

The table is followed by a button, which has its onclick attribute calling function sumup. Now when you click it, Javascript will fetch the values from the cells and write the total for each column in the last row of the table.

123.1445 * 6
27:-)89
306.282
?????

The basic script

The rows and cells properties are not universally supported, but neither is getElementsByTagName, and they are faster and much more elegant. Of course in real applications all have their place.

No table in real life has a varying number of cells across rows, but the script is simple enough to be set up so that any missing cells do not cause errors. During each inspection of a row (the outer while loop), the number of cells is the first item inspected, stored in j.

function sumup( o ) {
 var t = [], cell,
  row = document.getElementById( 'sumtable' ).rows,
  i = row.length - 1,
  lastrow = row[i];
 while(i--) {
  cell = row[i].cells; j = cell.length;
  while(j--) {
   if( !t[j] ) { t[j] = 0; }
   t[j] += parseFloat( cell[j].firstChild.nodeValue ) || 0;
  }
 }
 j = t.length; while(j--) {
  if( lastrow.cells[j] ) { lastrow.cells[j].firstChild.nodeValue = t[j]; }
 }
 o.disabled = true;
}

The function finishes off by disabling the button that invoked it. It can run only once.

Advanced tables

Semantically speaking, the last row is the table foot. And lo and behold, HTML provides a tag just for that: the <tfoot> should be used whenever possible, which is probably to say, when the function is enhanced to look beyond the safe haven of a single tbody.

A better function would also read from and write to elements within cells, perhaps with a special interest for <input type="text"> elements that users edit themselves.