Reputation: 171
I am attempting to collapse a table when the onclick event occurs. I iterate through the rows of a table and either set their visibility to collapse or to visible. If there is a table in one of the table data elements, setting the visibility of the row to visible doesn't affect the visibility of the table within. I tried to make the center loop recursive and call it on any inner table nodes, but that doesn't fix it. How can I fix this issue?
main.html
<html>
<head>
<title>Hello World</title>
</head>
<body>
<table class="collapsible" cellpadding="2" cellspacing="0" border="2" bgcolor="lightgrey">
<tr>
<td style="word-wrap: break-word;">datum 1</td>
<td style="word-wrap: break-word;">datum 2</td>
</tr>
<tr>
<td>
<table CELLPADDING="2" CELLSPACING="0" BORDER="2" BGCOLOR="lightgrey">
<tr>
<td style="word-wrap: break-word;">datum 3</td>
</tr>
<tr>
<td style="word-wrap: break-word;">datum 4</td>
</tr>
</table>
</td>
</tr>
<tr>
<td style="word-wrap: break-word;">datum 5</td>
<td style="word-wrap: break-word;">datum 6</td>
</tr>
</table>
<script>
var tbls = document.getElementsByClassName("collapsible");
var tblCnt = tbls.length;
init();
function init() {
var i;
for (i=0; i<tblCnt; i++) {
tbls[i].addEventListener("click", collapse);
}
}
function collapse() {
collapseAlg(this,1)
}
// start=0 -> collapse all rows, start=1 -> collapse all except the first row (assume no th)
function collapseAlg(tbl, start) {
console.log("called", tbl);
var rows = tbl.getElementsByTagName("tr");
var i;
var j;
var datum;
for (i = start; i < rows.length; i++) {
if (window.getComputedStyle(rows[i]).visibility === "collapse") {
rows[i].style.visibility = "visible";
tblss = rows[i].getElementsByTagName("table");
for (j=0; j < tblss.length; j++) {
collapseAlg(tblss[j],0);
}
} else {
rows[i].style.visibility = "collapse";
}
}
}
</script>
</body>
</html>
Upvotes: 1
Views: 306
Reputation: 35670
Great question. The issue is with this code:
var rows = tbl.getElementsByTagName("tr");
That retrieves all the table's TR elements, including those within sub-tables.
You want only the .collapsible table's rows. This is a little tricky, because tables automatically add TBODY elements if you haven't done so explicitly.
This gives the rows you need:
var rows = tbl.querySelectorAll(":scope > tbody > tr");
And you can get rid of this code:
tblss = rows[i].getElementsByTagName("table");
for (j=0; j < tblss.length; j++) {
collapseAlg(tblss[j],0);
}
Snippet:
var tbls = document.getElementsByClassName("collapsible");
var tblCnt = tbls.length;
init();
function init() {
var i;
for (i = 0; i < tblCnt; i++) {
tbls[i].addEventListener("click", collapse);
}
}
function collapse() {
collapseAlg(this, 1)
}
// start=0 -> collapse all rows, start=1 -> collapse all except the first row (assume no th)
function collapseAlg(tbl, start) {
console.log("called", tbl);
var rows = tbl.querySelectorAll(":scope > tbody > tr");
var i;
var j;
var datum;
for (i = start; i < rows.length; i++) {
if (window.getComputedStyle(rows[i]).visibility === "collapse") {
rows[i].style.visibility = "visible";
} else {
rows[i].style.visibility = "collapse";
}
}
}
<table class="collapsible" cellpadding="2" cellspacing="0" border="2" bgcolor="lightgrey">
<tr>
<td style="word-wrap: break-word;">datum 1</td>
<td style="word-wrap: break-word;">datum 2</td>
</tr>
<tr>
<td>
<table CELLPADDING="2" CELLSPACING="0" BORDER="2" BGCOLOR="lightgrey">
<tr>
<td style="word-wrap: break-word;">datum 3</td>
</tr>
<tr>
<td style="word-wrap: break-word;">datum 4</td>
</tr>
</table>
</td>
</tr>
<tr>
<td style="word-wrap: break-word;">datum 5</td>
<td style="word-wrap: break-word;">datum 6</td>
</tr>
</table>
Upvotes: 2