Search code examples
javascripthtmlhtml-table

Why can't I get to table body element with JavaScript?


I have a simple table, and this table contains thead, tbody and tfoot sections. In JavaScript, I want to be able to access each of these parts to set some attributes.

I try to get the the parts with table.tHead, table.tBody and table.tFoot respectively.

This works for tHead and tFoot just fine, but tBody always returns undefined.

Looking inside the table object with the browser debugger, I can see that table.childNoes and table.children shows all the table parts, including tbody.

Strangely, if I access the tbody section using its ID with document.getElementById("TB") it works just fine.

Can anyone explain this to me? Here's the source HTML with JavaScript:

let table1 = document.getElementById("TBL1");

if (typeof(table1) != "undefined") {
  console.log(" - table element 'TBL1' acquired");

  let thead = table1.tHead;
  if (typeof(thead) != "undefined") {
    console.log(" - table element table1.tHead acquired,");
    thead.style.color = "#ffff50";
    console.log("   thead color changed to " + thead.style.color);
  } else
    console.log(" OOPS - could not access table table1.tHead");


  let tbody = table1.tBody;
  if (typeof(tbody) != "undefined") {
    console.log(" - table element table1.tBody acquired,");
    tbody.style.color = "#504020";
    console.log("   tbody color changed to " + tbody.style.color);
  } else
    console.log(" OOPS - could not access table table1.tBody");

  let tfoot = table1.tFoot;
  if (typeof(tfoot) != "undefined") {
    console.log(" - table element table1.tFoot acquired,");
    tfoot.style.color = "#ffff50";
    console.log("   tfoot color changed to " + tfoot.style.color);
  } else
    console.log(" OOPS - could not access table table1.tFoot");
} else
  console.log("OOP - Couldn't acquire TBL1 table");

if (typeof(tbody) == "undefined") {
  tbody = document.getElementById("TB");
  if (typeof(tbody) != "undefined")
    console.log(" - table element table1.tBody acquired using getElementById('TB'),");
  tbody.style.color = "#504020";
  console.log("   tbody color changed to " + tbody.style.color);
}

console.log(" - Done with table element access test");
thead,
tfoot {
  background-color: #3f87a6;
  color: #ffff;
}

tbody {
  background-color: #64d0c0;
  color: #ffff;
}

caption {
  padding: 10px;
  caption-side: bottom;
}

table {
  border-collapse: collapse;
  border: 2px solid rgb(120, 120, 120);
  letter-spacing: 1px;
  font-family: sans-serif;
  font-size: 0.8rem;
}

td,
th {
  border: 1px solid rgb(120, 120, 120);
  padding: 5px 10px;
}

td {
  text-align: center;
}
<body>
  <script>
    document.body.style.backgroundColor = "#A0C0C0";
    console.log("Testing table element access -");
  </script>

  <div ID="DIV1">
    <table ID="TBL1" style="margin-left: 100px; margin-top: 100px;">
      <caption>
        Council budget (in £) 2018
      </caption>

      <thead ID="TH">
        <tr ID="HROW">
          <td>Items</td>
          <td scope="col">Expenditure</td>
        </tr>
      </thead>

      <tbody ID="TB">
        <tr ID="BROW1">
          <td scope="row">Donuts</td>
          <td>3,000</td>
        </tr>
        <tr ID="BROW2">
          <td scope="row">Stationery</td>
          <td>18,000</td>
        </tr>
      </tbody>

      <tfoot ID="TF">
        <tr ID="FROW">
          <td scope="row">Totals</td>
          <td>21,000</td>
        </tr>
      </tfoot>
    </table>
</body>


Solution

  • There is no tBody property on a HTMLTableElement. There can be multiple tbody elements within a single table, so there's a tBodies collection which returns a NodeList of them all.

    In your example, as you know there is only a single tbody instance, you can access the 0th element by index:

    let table1 = document.getElementById("TBL1");
    
    if (table1) {
      let thead = table1.tHead;
      if (thead) {
        thead.style.color = "#ffff50";
      }
    
      let tbody = table1.tBodies[0]; // Note the property name and index accessor here
      if (tbody) {
        tbody.style.color = "#504020";
      }
    
      let tfoot = table1.tFoot;
      if (tfoot) {
        tfoot.style.color = "#ffff50";
      }
    }
    thead,
    tfoot {
      background-color: #3f87a6;
      color: #ffff;
    }
    
    tbody {
      background-color: #64d0c0;
      color: #ffff;
    }
    
    caption {
      padding: 10px;
      caption-side: bottom;
    }
    
    table {
      border-collapse: collapse;
      border: 2px solid rgb(120, 120, 120);
      letter-spacing: 1px;
      font-family: sans-serif;
      font-size: 0.8rem;
    }
    
    td,
    th {
      border: 1px solid rgb(120, 120, 120);
      padding: 5px 10px;
    }
    
    td {
      text-align: center;
    }
    <div id="DIV1">
      <table id="TBL1" style="margin-left: 100px; margin-top: 100px;">
        <caption>
          Council budget (in £) 2018
        </caption>
        <thead id="TH">
          <tr ID="HROW">
            <td>Items</td>
            <td scope="col">Expenditure</td>
          </tr>
        </thead>
        <tbody id="TB">
          <tr id="BROW1">
            <td scope="row">Donuts</td>
            <td>3,000</td>
          </tr>
          <tr id="BROW2">
            <td scope="row">Stationery</td>
            <td>18,000</td>
          </tr>
        </tbody>
        <tfoot id="TF">
          <tr id="FROW">
            <td scope="row">Totals</td>
            <td>21,000</td>
          </tr>
        </tfoot>
      </table>
    </div>

    If there will ever be multiple tbody elements within your table, then you could implement a loop to iterate through them all.

    Also, as an aside, note that it's generally good practice to keep attributes in your HTML in lowercase, and to avoid using inline style attributes. Use external stylesheets for all styling.