Determining cells that reside in a table column underneath a cell
in the following table:
<table>
<thead>
<tr>
<th>Th1</th>
<th colspan='2'>Th23</th>
<th>Th4</th>
</tr>
</thead>
<tbody>
<tr>
<td>Td1</td>
<td>Td2</td>
<td>Td3</td>
<td>Td4</td>
</tr>
</tbody>
</table>
For the table cell containing text "Th23", I'd like to know which cells reside beneath it. In this case, the answer would be the cells containing text "Td2", and "Td3" respectively.
Are there any DOM properties or built-ins that help with this type of calculation?
@Matt McDonald has a more general solution.
This is what I ended up with:
开发者_如何学C// get tbody cell(s) under thead cell (first arg)
// if rowIndex===undefined, get from all rows; otherwise, only that row index
// NOTE: does NOT work if any cell.rowSpan != 1
var columnCells = function( th, rowIndex ) {
// get absolute column for th
for( var absCol=0, i=0; true; i++ ) {
if( th.parentNode.cells[i] == th ) break;
absCol += th.parentNode.cells[i].colSpan;
}
// look in tBody for cells; all rows or rowIndex
var tBody = th.parentNode.parentNode.nextSibling;
var cells = [];
for( var r=((rowIndex==undefined)?0:rowIndex); true; r++ ) {
if( rowIndex!==undefined && r>rowIndex ) break;
if( rowIndex==undefined && r>=tBody.rows.length ) break;
for( var c=0; true; c+=tBody.rows[r].cells[c].colSpan ) {
if( c < absCol ) continue;
if( c >= absCol+th.colSpan ) break;
cells.push(tBody.rows[r].cells[c]);
}
}
return cells;
}
Right off the bat, you need to do three things:
- Give the table an
id
attribute for easy selection. - Give the target cell an
id
attribute for easy selection as well. - Select the cell's
parentNode
(row)
These three things will enable easier table-related calculations.
Next up is a function that grabs pseudo-properties of the specified cell. In this case, we're looking for its "start index" (in terms of columns), its "end index" (in terms of columns), and its "width" (end - start, in columns as well).
From there, you can traverse through the table's rows and check which cells fall between the start and the end indexes.
HTML:
<table id="foo">
<colgroup span="1">
<colgroup span="2">
<colgroup span="1">
<thead>
<tr>
<th>foo</th>
<th id="example" colspan="2">bar</th>
<th>baz</th>
</tr>
</thead>
<tbody>
<tr>
<td>bing</td>
<td>bang</td>
<td>boom</td>
<td>bong</td>
</tr>
</tbody>
</table>
JS (bear with me):
function getCellSpanProps(table, row, cell)
{
var isRow = (function()
{
var i = 0, currentRow;
for(i;i<table.rows.length;i++)
{
currentRow = table.rows[i];
if(currentRow === row)
{
return true;
}
currentRow = null;
}
return false;
}()),
cellHasCorrectParent, i = 0,
currentCell, colspanCount = 0,
props;
if(isRow)
{
cellHasCorrectParent = (function()
{
return cell.parentNode === row;
}());
if(cellHasCorrectParent)
{
for(i;i<row.cells.length;i++)
{
currentCell = row.cells[i];
if(currentCell === cell)
{
props = {"start": colspanCount,
"end": colspanCount + cell.colSpan,
"width": (colspanCount + cell.colSpan) - colspanCount};
break;
}
colspanCount += currentCell.colSpan;
currentCell = null;
}
row = null;
}
return props;
}
}
function findCellsUnderColumn(table, props)
{
var i = 0, j = 0, row, cell,
colspanCount = 0, matches = [],
blacklist = {"": true, "NaN": true, "null": true, "undefined": true,
"false": true};
if(blacklist[props.start] || blacklist[props.end] || blacklist[props.width])
{
return false;
}
for(i;i<table.rows.length;i++)
{
row = table.rows[i];
colspanCount = 0;
for(j=0;j<row.cells.length;j++)
{
cell = row.cells[j];
if(colspanCount >= props.start && colspanCount < props.end)
{
matches.push(cell);
}
colspanCount += cell.colSpan;
cell = null;
}
row = null;
}
return matches;
}
var table = document.getElementById("foo"),
example = document.getElementById("example"),
targetRow = example.parentNode,
props = getCellSpanProps(table, targetRow, example),
matches = findCellsUnderColumn(table, props);
console.log(matches);
Demo: http://jsbin.com/ohohew/edit#javascript,html
This will determine which cells reside inside the particular column you're looking for (including the example). You can customize the function to fit your needs if that's not exactly what you're looking for.
You need to know the column index of your cell. I'll name it ci
. Then read its colspan (if empty, set it to 1). Then find the cells on the next line that have a column index >= ci
and < ci + colspan
. For such a complex need, using a JS framework is very useful. I'll suppose you can use JQuery, since it's the most frequently used.
Computing the colum index has several solutions on SO.
Reading the colspan attribute is just cell.attr('colspan')
with jQuery.
Finding the next row is cell.closest('tr').next('tr')
.
The last step is to iterate over every element of the line and compute their column index. You could use the same function as above, but if it's not efficient enough, it should be easy to adapt its code so that it does not return an integer, but add elements to an array.
精彩评论