GrimThor3
GrimThor3

Reputation: 171

Collapsing tables within tables

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

Answers (1)

Rick Hitchcock
Rick Hitchcock

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

Related Questions