I have a HTML table that contains both ROWSPANs and COLSPANs.
How can I find each cell\'s \"visual location\" using jQuery?
For example, here\'s a visual rep
Here's my solution:
function getCellLocation(cell) {
var cols = cell.closest("tr").children("td").index(cell);
var rows = cell.closest("tbody").children("tr").index(cell.closest("tr"));
var coltemp = cols;
var rowtemp = rows;
cell.prevAll("td").each(function() {
cols += ($(this).attr("colspan")) ? parseInt($(this).attr("colspan")) - 1 : 0;
});
cell.parent("tr").prevAll("tr").each(function() {
//get row index for search cells
var rowindex = cell.closest("tbody").children("tr").index($(this));
// assign the row to a variable for later use
var row = $(this);
row.children("td").each(function() {
// fetch all cells of this row
var colindex = row.children("td").index($(this));
//check if this cell comes before our cell
if (cell.offset().left > $(this).offset().left) {
// check if it has both rowspan and colspan, because the single ones are handled before
var colspn = parseInt($(this).attr("colspan"));
var rowspn = parseInt($(this).attr("rowspan"));
if (colspn && rowspn) {
if(rowindex + rowspn > rows)
cols += colspn;
}
if(rowspn && rowindex + rowspn > rows) cols +=1;
}
});
});
I'm checking for cells which have both colspan and rowspan, because the rest are handled by the first five lines of this code. If the cells have both rowspan and colspan, they should be effecting other cells that are not below OR aside this cell, so I need to search for every cell's previous cells for interaction.
your solution my proposed table design
+--+--+--+--+--+ +--+--+--+--+--+
| |A |B |C |D | | |A |B |C |D | length 5 vs 5
+--+--+--+--+--+ +--+--+--+--+--+
|1 |A1|B1 |D1| |1 |A1|B1|//|D1|
+--+--+--+--+ + +--+--+--+--+--+
|2 |A2 |C2| | |2 |A2|//|C2|//| length 3 vs 5
+--+ +--+ + +--+--+--+--+--+
|3 | |C3| | |3 |//|//|C3|//|
+--+--+--+--+--+ +--+--+--+--+--+
|4 |A4|B4|C4|D4| |4 |A4|B4|C4|D4|
+--+--+--+--+--+ +--+--+--+--+--+
|XYZ | |XY|//|//|//|//| length 1 vs 5
+--+--+--+--+--+ +--+--+--+--+--+
// cells labeled '//' above have this class
td.stuffing { display: none; }
Do you see what I did there?
This is the third row, for example:
<tr>
<th>2</th>
<td rowspan="2" colspan="2">A2</td>
<td class="stuffing"></td>
<td>C2</td>
<td class="stuffing"></td>
</tr>
Now the function to retrieve correct index is very simple.
function getCellLocation(cell) {
return {row:cell.parentNode.rowIndex, cell:cell.cellIndex}
}
function getSmartCell(table, row, col) {
var cell = table.rows[row].cells[col];
if (cell.className.indexOf("stuffing") == -1) return cell;
// traverse Left
while ((row>0) && (col>0) && (cell.className.indexOf("stuffing") >= 0)) {
cell = table.rows[row].cells[--col];
}
// roll back one cell if no colSpan is found
if (cell.colSpan == 1) cell = table.rows[row].cells[++col];
// traverse Up
while ((row>0) && (col>0) && (cell.className.indexOf("stuffing") >= 0)) {
cell = table.rows[--row].cells[col];
}
return cell;
}
Usage:
var tb = document.querySelector("table");
getCellLocation(getSmartCell(tb,3,2)); // {row: 2, cell: 1}
ATTENTION
I have just checked the code of getSmartCell
and it returns wrong result if there are two neighbouring rowspans. I need to fix this.
Here is an example https://jsfiddle.net/goua3m13/
for this specific layout (i.e. if your first row doesn't have colspan and more or less uniform cell borders) you may do it this way:
function getCellLocation(cell)
{
var row_number = cell.parentNode.rowIndex;
var col_number = "";
$(cell).parents('table').find('tr:first th').each( function()
{
if (cell.offsetLeft >= this.offsetLeft)
{
col_number = $(this).text();
}
else return false;
});
return col_number + row_number;
}
if you want numeric column change it to
var col_number = 0;
...
if (cell.offsetLeft >= this.offsetLeft)
{
col_number++;
}
Here a jQuery solution that is able to handle complex table structure. This solution use the Open Source WxT Table Parser available here: https://raw.github.com/wet-boew/wet-boew/master/src/js/dependencies/parserTable.js
You will find the documentation in the Table Usability Concept Github Repository. Use the API documentation that is under "Table Parser - WET 3.0 release".
The table parsing is done by using the HTML tabular markup and the visual relationships between the data cell (td) and the header cell (th)
// Used to get the reference to the WxT table parser
var _pe = window.pe || {
fn : {}
};
// For each table elements
$('table').each(function () {
var $tbl = $(this);
// Parse the table
_pe.fn.parsertable.parse($tbl);
// For each data cell
$('td', $tbl).each(function () {
var $td = $(this),
tblparser;
// Get the API structure as defined under "Table Parser - WET 3.0 release" (https://github.com/duboisp/Table-Usability-Concept/blob/master/API/td.md#table-parser---wet-30-release)
tblparser = $td.data().tblparser;
// Set the cell location (x, y)
$td.html(tblparser.row.rowpos + ', ' + tblparser.col.start);
});
});
You will find a working example here: http://jsfiddle.net/TVttA/
Cheers
:-)
Since the accepted answer is missing a return
statement and only works with tbody and td (and not with thead and th) I did some slight adjustments to make it work:
function getCellLocation(cell) {
var cols = cell.closest("tr").children("th, td").index(cell);
var rows = cell.closest("thead, tbody").children("tr").index(cell.closest("tr"));
cell.prevAll("th, td").each(function() {
cols += ($(this).attr("colspan")) ? parseInt($(this).attr("colspan")) - 1 : 0;
});
cell.parent("tr").prevAll("tr").each(function() {
//get row index for search cells
var rowindex = cell.closest("thead, tbody").children("tr").index($(this));
// assign the row to a variable for later use
var row = $(this);
row.children("th, td").each(function() {
//check if this cell comes before our cell
if (cell.offset().left > $(this).offset().left) {
// check if it has both rowspan and colspan, because the single ones are handled before
var colspn = parseInt($(this).attr("colspan"));
var rowspn = parseInt($(this).attr("rowspan"));
if (rowspn && rowindex + rowspn > rows) {
cols += colspn ? colspn : 1;
}
}
});
});
return cols;
}