I have the following code:
myText = document.getElementById("myText") texts = myText.getElementsByTagName("text"); let div = document.createElement("div"); console.log("Texts length: " + texts.length); for (let j = 1; j < texts.length; j++) { div.appendChild(texts[j]); } div.style.display = "none"; myText.appendChild(div);
<div id ="myText"> <text text-anchor="middle" x="193.25" y="-178.3" font-family="Times,serif" font-size="14.00">Running</text> <text text-anchor="middle" x="75.5" y="-152.8" font-family="Times,serif" font-size="14.00"> <onentry > </text> <text text-anchor="middle" x="75.5" y="-137.8" font-family="Times,serif" font-size="14.00">  <log expr=' 'Running!''  ></text> <text text-anchor="middle" x="75.5" y="-106.8" font-family="Times,serif" font-size="14.00">  </log></text> <text text-anchor="middle" x="75.5" y="-75.8" font-family="Times,serif" font-size="14.00"></onentry></text> </div>
When the function ends, I have the following result.
<div id="myText"> <text text-anchor="middle" x="193.25" y="-178.3" font-family="Times,serif" font-size="14.00">Running</text> <text text-anchor="middle" x="75.5" y="-137.8" font-family="Times,serif" font-size="14.00"> <log expr=' 'Running!'' ></text> <text text-anchor="middle" x="75.5" y="-75.8" font-family="Times,serif" font-size="14.00"></onentry></text> <div style="display: none;"> <text text-anchor="middle" x="75.5" y="-152.8" font-family="Times,serif" font-size="14.00"> <onentry > </text><text text-anchor="middle" x="75.5" y="-106.8" font-family="Times,serif" font-size="14.00"> </log></text></div> </div>
Two out of the four text elements were not properly inserted into the new div. I am not sure why, can anyone help?
@Pilchard's answer is a direct response to your question. This, however, is a method of sidestepping the issue by using querySelectorAll which returns a static NodeList instead of a live HTMLCollection.
When you simplify a bit and use a forEach
loop, you eliminate the need for a for
loop and cuts the code down a bit. I am populating a new div with the data for demonstration
myText = document.getElementById("newText") texts = document.querySelectorAll("text"); let div = document.createElement("div"); texts.forEach(el => div.appendChild(el)); document.getElementById("myText").style.display = "none"; myText.appendChild(div);
text { display: block; }
<div id="myText"> <text text-anchor="middle" x="193.25" y="-178.3" font-family="Times,serif" font-size="14.00">Running</text> <text text-anchor="middle" x="75.5" y="-152.8" font-family="Times,serif" font-size="14.00"> <onentry > </text> <text text-anchor="middle" x="75.5" y="-137.8" font-family="Times,serif" font-size="14.00">  <log expr=' 'Running!''  ></text> <text text-anchor="middle" x="75.5" y="-106.8" font-family="Times,serif" font-size="14.00">  </log></text> <text text-anchor="middle" x="75.5" y="-75.8" font-family="Times,serif" font-size="14.00"></onentry></text> </div> <div id="newText"> </div>
There are a number of things going wrong in your code.
First of all, you need to declare your variables.
const myText = ...
const texts = ...
Next, getElementsByTagName()
returns a liveHTMLCollection which mutates to match changes to the DOM. This means that as you move elements to the new <div>
you alter the length of the queried collection causing your loop to end before it's had a chance to iterate the entire collection.
If you move your console.log()
inside the loop you'll see the length is one shorter on each iteration.
const myText = document.getElementById("myText"); const texts = myText.getElementsByTagName("text"); const div = document.createElement("div"); for (let j = 1; j < texts.length; j++) { console.log(`Texts length: ${texts.length}, j: ${j}`); div.appendChild(texts[j]); } console.log(`Texts length: ${texts.length}`);
<div id ="myText"> <text text-anchor="middle" x="193.25" y="-178.3" font-family="Times,serif" font-size="14.00">Running</text> <text text-anchor="middle" x="75.5" y="-152.8" font-family="Times,serif" font-size="14.00"> <onentry > </text> <text text-anchor="middle" x="75.5" y="-137.8" font-family="Times,serif" font-size="14.00">  <log expr=' 'Running!''  ></text> <text text-anchor="middle" x="75.5" y="-106.8" font-family="Times,serif" font-size="14.00">  </log></text> <text text-anchor="middle" x="75.5" y="-75.8" font-family="Times,serif" font-size="14.00"></onentry></text></div>
You can avoid this by converting the returned HTMLCollection to an array, for example with spread syntax .
const texts = [...myText.getElementsByTagName("text")];
Lastly, you're starting your loop at 1
which skips the first element because arrays (and array-likes like HTMLCollections) are zero indexed in javascript.
Working final snippet
const myText = document.getElementById("myText"); const texts = [...myText.getElementsByTagName("text")]; const div = document.createElement("div"); for (let j = 0; j < texts.length; j++) { div.appendChild(texts[j]); } div.className='new'; myText.appendChild(div);
.new { background-color: aqua; border: 1px solid darkgray; }
<div id ="myText"> <text text-anchor="middle" x="193.25" y="-178.3" font-family="Times,serif" font-size="14.00">Running</text> <text text-anchor="middle" x="75.5" y="-152.8" font-family="Times,serif" font-size="14.00"> <onentry > </text> <text text-anchor="middle" x="75.5" y="-137.8" font-family="Times,serif" font-size="14.00">  <log expr=' 'Running!''  ></text> <text text-anchor="middle" x="75.5" y="-106.8" font-family="Times,serif" font-size="14.00">  </log></text> <text text-anchor="middle" x="75.5" y="-75.8" font-family="Times,serif" font-size="14.00"></onentry></text> </div>
All that being said, I'm not sure what you're doing with your <text>
elements but it's outside the scope of you question so I'll leave that to you.
I think I figured it out. Basically append child also removes the element from its previous position.
Thereby changing length and the element at index j, a better approach would be to store length and then get first element since the list becomes shorter
length = texts.length; for(let j = 1; j < length; j++){ div.appendChild(texts[1]); }
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.