Ad

Nodes Disappear From Loop When Appended

- 1 answer

Simplest Solution

I am trying to answer Hide second line of text with CSS with a JS version

Why does the second line disappear from my loop? Is the textnode stuck to the BR for some reason?

I want to hide the BR and subsequent lines but I do not move the second line to the span

Expected result is when BR is encountered, it and all following nodes are moved to the span and at the end the span is appended to the div where the br used to be, making the second line red in this case

I played with cloneNode which worked better but I wanted to move the nodes, not clone them. I also thought about substring the innerHTML but was worried that the various rendering and toString of BR is not reliable

Input:

<div class="site-info">The quick brown fox <br>Jumps over the lazy dog</div>

Expected output:

<div class="site-info">The quick brown fox <span class="hide"><br>Jumps over the lazy dog</span></div>

Attempt:

var si = document.querySelector(".site-info")
var nodes = si.childNodes;
var span = document.createElement("span");
span.className="hide"
var found = false;
nodes.forEach(n => {
  console.log(n.tagName || "No tag",n.wholeText || "No text")
  if (n.tagName==="BR") { // first br found
    found = true; 
  }  
  if (found) { // from now on to end of all nodes
    span.appendChild(n) // n.cloneNode(true) 
  }
});
si.appendChild(span)
.hide { color:red }/* display: none }*/
<div class="site-info">The quick brown fox <br>Jumps over the lazy dog</div>


Expected result NOTE: color:red will be display:none in real version, resulting in the second line appearing WITH the BR if display:none is removed by code

.hide { color:red }
<div class="site-info">The quick brown fox <span class="hide"><br>Jumps over the lazy dog</span></div>

Ad

Answer

When you do a console.log(nodes) before the the loop you will notice that the span is already included as a childNode.

enter image description here

That seems to mess with the logic of span.appendChild while looping through the nodes.

Edit: As per the comments, when calling appendChild for the br tag, the elements gets removed from the DOM which alteres the reference inside the nodes array and causes the two text nodes to combine as they are not seperated anymore. So the loop will not reach the former 3rd iteration anymore as that array element does not exist anymore.

If you pull the logic for appending the nodes outside the loop it works:

var si = document.querySelector(".site-info")
var nodes = si.childNodes;
var span = document.createElement("span");
span.className = "hide"
var found = false;
let childs = [];
nodes.forEach((n, i) => {
  if (n.tagName === "BR") {
    found = true;
  }
  if (found) {
    childs.push(n);
  }
});
if (childs.length > 0) {
  childs.forEach((n) => {
    span.appendChild(n);
  });
  si.appendChild(span);
}
.hide {
  color: red
}
<div class="site-info">The quick brown fox <br>Jumps over the lazy dog</div>

That being said I actually haven't found a reason for that happening so there might be a more elegant solution to that.

Ad
source: stackoverflow.com
Ad