Home > OS >  Mystery tbody tag being inserted
Mystery tbody tag being inserted

Time:03-14

I have a custom component I'm working on and I borrowed code from one project verbatim from another. Here's the trouble area:

<style>
    #history tr:nth-child(even) {background-color: #f2f2f2;}
</style>
<div  style="height:280px;overflow:auto;" id="myscroller">
    <table id="history" style="width:100%">
    </table>
</div>

Then later the table is appended to with this:

this.shadowRoot.querySelector('#history').innerHTML  = `<tr><td>Term ${this._term}: ${text}</td></tr>`;

All of it works. However, I'm not getting my alternating highlighting because in project #2 the row is being wrapped with <tbody></tbody> tags. I have no use of tbody anywhere, but it crops up in just the new page I'm toying with. How do I suppress the insertion of <tbody> tags when setting innerHTML to have a <tr>?

I know someone will ask what happens when use = instead of =. It's got the same problem.

Summary: xxx.innerHTML = `<tr><td>text</td></tr>` produces different results in different projects. One of the two following:

<table><tr><td>text</td></tr></table>
<table><tbody><tr><td>text</td></tr></tbody></table>

Edit:

According to what I'm reading in the comments, if I append multiple rows by appending HTML I should get the following: https://i.imgur.com/7PDaMxW.png

But there doesn't seem to be any way to not get it to bracket it with ... except what appears to happen on another page (and apparently by accident).

This table was created identically: https://i.imgur.com/Wc9i18e.png Maybe the better question to ask is "how did I manage to do it the first time around? What did I set in CSS or something that's suppressing the insertion of a tbody?"

CodePudding user response:

The browser infers the existence of a <tbody>. You cannot remove it.

A thing to keep in mind is that people have been writing broken HTML since the dawn of the web. Browser makers have chosen to handle that problem by making browsers do more than meet page authors halfway.

Try this experiment.

  1. Create a bare HTML page like this:
<!DOCTYPE html>
<html>
    <body>
        <table>
            <tr>
                <td>one</td>
            </tr>
        </table>
    </body>
</html>
  1. Open that page in your browser, and use Dev Tools to inspect it. You'll see a <tbody>.

CodePudding user response:

It is normal behaviour for most browsers. It is inserted browser during processing your DOM. For more details refer to official MDN. It is impossible to suppress <tbody>, maybe you can use it another way. What about using in CSS #history > tbody > tr:nth-child(even) first collect all tr in one string IN JAVASCRIPT and then add it using innerHTML to #history

CodePudding user response:

Here is a little snippet that illustrates the discussion in the comments:

const tbl=document.getElementById("history");

"abc".split("").forEach((v,i)=>
tbl.innerHTML =`<tr><td>Term ${i}: ${v}</td></tr>`);

console.log(tbl.innerHTML);

// A better approach would be:

tbl.innerHTML="abc".split("").map((v,i)=>
`<tr><td>Term ${i}: ${v}</td></tr>`).join("");

console.log(tbl.innerHTML);

// A third solution might be:

const tbd=document.createElement("tbody");
tbl.replaceChildren(tbd);

"abc".split("").forEach((v,i)=>
tbd.innerHTML =`<tr><td>Term ${i}: ${v}</td></tr>`);

console.log(tbl.innerHTML);
<table id="history"></table>

The first approach is bad for two reasons:

  1. It forces the entire innerHTML of tbl to be parsed over and over again (for each new <tr>).
  2. Each time <tr> is to be added to the <table> a new <tbody> will be wrapped around it.

The second approach is better, as it will only once add elements into the table. The <tbody> will be wrapped around the inserted elements, but only once!

In the third way we will at first insert a <tbody> element into the table. The reference to the <tbody> tbd will then be parsed again - in a redundant way, but there will only be no further <tbody> sections added!

  • Related