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.
- Create a bare HTML page like this:
<!DOCTYPE html>
<html>
<body>
<table>
<tr>
<td>one</td>
</tr>
</table>
</body>
</html>
- 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:
- It forces the entire
innerHTML
oftbl
to be parsed over and over again (for each new<tr>
). - 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!