Reputation: 9830
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>
Upvotes: 7
Views: 13276
Reputation: 544
The simplest is to use append method from Element and use it like:
Element.prototype.append.apply(domElement, arrayOfElements);
Upvotes: 0
Reputation: 4187
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)
Upvotes: 6
Reputation: 6419
You are changing the collection on the fly (in the loop itself) by removing items from it, that's why it acts wired. Here's the code that should actually work:
var wrapper = document.createElement('div'),
myClass = document.getElementsByClassName('myClass'),
myClassParent = myClass[0].parentNode;
while (myClass.length) {
wrapper.appendChild(myClass[0]);
}
myClassParent.appendChild(wrapper);
wrapper.setAttribute('id','wrapper');
https://jsfiddle.net/byd9fer3/1/
Upvotes: 1
Reputation: 26
I have a simple working version for you with code. Thanks
<html>
<body>
<button onclick="myFunction()">Try it</button>
<p><strong>Note:</strong> The getElementsByClassName() method is not supported in Internet Explorer 8 and earlier versions.</p>
<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>
<script>
function myFunction() {
var wrapper = document.createElement('div');
var x = document.getElementsByClassName("myClass");
for(var i=0; i < x.length;++i){
var newdiv = document.createElement('div');
newdiv.appendChild(document.createTextNode(x[i].innerHTML));
wrapper.appendChild(newdiv);
}
document.body.appendChild(wrapper);
}
</script>
</body>
</html>
Upvotes: 0
Reputation: 19237
Look at your for loop step by step:
1. myClass[First, Second, Third, Fourth, Fifth]; wrapper[] ; key = 0
2. myClass[Second, Third, Fourth, Fifth] ; wrapper[First]; key = 1
Now instead of Second, you'll take Third, because key is 1, but you'll need to take the item at index 0. This also gives the fix: always take the item at position 0.
var wrapper = document.createElement('div'),
myClass = document.getElementsByClassName('myClass');
myClass[0].parentElement.appendChild(wrapper);
wrapper.id = 'wrapper';
for (var i = 0; i < myClass.length; i++) {
wrapper.appendChild(myClass[0]);
}
#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>
Upvotes: 3