I have 5 div's
created in HTML, and I want to add all of them into a div
wrapper I created in JavaScript. I tried looping through the 5 div's
via a for-in
loop, then append the div
as a child of the wrapper
.
For some reason, the for
loop changes the 5 div's
order and doesn’t append all of them in wrapper
. How can I add all div's
to wrapper
, keeping the (HTML) order, using JavaScript?
(Please don’t post JQuery answers because that isn’t the question. I want JavaScript answers only.)
var wrapper = document.createElement('div'), myClass = document.getElementsByClassName('myClass'); myClass[0].parentElement.appendChild(wrapper); wrapper.id = 'wrapper'; for (var key in myClass) { if (!myClass.hasOwnProperty(key)) continue; wrapper.appendChild(myClass[key]); }
#wrapper { border: 2px solid green; color: brown; }
<div class="myClass">First</div> <div class="myClass">Second</div> <div class="myClass">Third</div> <div class="myClass">Fourth</div> <div class="myClass">Fifth</div>
Advertisement
Answer
The document.getElementsByClassName
method returns an HTMLCollection
-object, which is similar to an array, as in it has numeric keys which should be used.
e.g. for (var i = 0; i < myClass.length; ++i)
Once you use an incremental numeric index, you’ll notice it actually behaves the same as your key in myClass
, which is rather logical, as the key
is the numeric index.
What is happening is that an HTMLCollection
represents elements in document order (a so called live list, which reflects the changes in the DOM) and you are moving them around by appending them to the wrapper element (hence the order within the HTMLCollection
changes too).
There are several tricks to work around this, the one closest to your current setup would be to walk through the HTMLCollection
from end to start and insertBefore
instead of appendChild
for (var len = myClass.length - 1; len >=0; --len) { wrapper.insertBefore(myClass[len], wrapper.firstChild); }
This works because the wrapper is (in your example) after the elements you’re moving into it, therefor not changing the order of the elements.
There is another (easier) approach: document.querySelectorAll
.
The querySelectorAll
method returns a (static) NodeList
, so you can safely assume the order will not change while you move nodes around.
The syntax is (IMHO) more convenient than getElementsByClassname
, as it uses CSS Selectors
(much like the popular javascript framework we won’t mention)