Skip to content Skip to sidebar Skip to footer

Why Is This While Loop Infinite? JavaScript AppendChild

I swear this was just working fine a few days ago... elm = document.querySelectorAll(selector); var frag = document.createDocumentFragment(); while (elm[0]){ frag.appendChild(e

Solution 1:

From the MDN Docs

Element.querySelectorAll

Summary

Returns a non-live NodeList of all elements descended from the element on which it is invoked that match the specified group of CSS selectors.

Syntax

elementList = baseElement.querySelectorAll(selectors);

where

  • elementList is a non-live list of element objects.
  • baseElement is an element object.
  • selectors is a group of selectors to match on.

From the docs above you can see it does not automatically remove it when you append it to another element since it is non live. Run a demo to show that feature.

var selector = "div";
elm = document.querySelectorAll(selector);
var frag = document.createDocumentFragment();
console.log("before",elm.length);
frag.appendChild(elm[0]);
console.log("after",elm.length);

When the code above runs, in the console you get.

before    3
after     3

If you want to do the while loop, convert to an array and shift() the items off

var selector = "div";
var elmNodeLIst = document.querySelectorAll(selector);
var frag = document.createDocumentFragment();
var elems = Array.prototype.slice.call(elmNodeLIst );
while (elems.length) {
    frag.appendChild(elems.shift());
}
console.log(frag);

Solution 2:

You are appending the first item in the node list, over and over and over. You never removing any items from the array, but always adding the first one to the fragment. And the first one is always the same.

elm = document.querySelectorAll(selector);
var frag = document.createDocumentFragment();
while (elm.length){
    frag.appendChild(elm.shift());
}

This may be closer to what you meant to do. We can use while (elm.length) because as items get removed form the array, eventually length will be zero which is a flasy value and the loop will stop.

And we use elm.shift() to fetch the item from the array because that method will return the item at index zero and remove it from the array, which gives us the mutation of the original array we need.


I think you thought this might work because a node can only have one parent. Meaning adding somewhere removes it from the previous parent. However, elm is not a DOM fragment. It's just a aray (or perhaps a NodeList) that holds references to element. The array is not the parent node of these elements, it just holds references.

Your loop might work if you had it like this, since you are query the parent node each time for its children, a list of node that will actually change as you move around:

elm = document.getElementById(id);
var frag = document.createDocumentFragment();
while (elm.children[0]){
    frag.appendChild(elm.children[0]);
}

Solution 3:

I wouldn't have expected it to work in the first place.

Your elm array is initialized, and never updated. Even if the result from running document.querySelectorAll(selector); would return something different, this doesn't change your current references in the array.

You would either need to rerun the selector, or manually remove the first element in the array after appending it.


Solution 4:

elm[0] is static and unchanging in above code fix is as below

elm = document.querySelectorAll(".container");
var frag = document.createDocumentFragment();
console.log(elm);
var i=0;
while (elm[i]){
    frag.appendChild(elm[i++]);
}

Solution 5:

I didn't actually focus much on the code (and if it made sense -judging from the comments- or not); but if this worked a few days ago then the problem is in the input you are giving to your code selector.

That's when Unit Testing comes in handy. If you can remember the input with which the code worked, then you can make it work again and start debugging from there.

Otherwise, you are just lying to yourself.


Post a Comment for "Why Is This While Loop Infinite? JavaScript AppendChild"