Strange behavior when iterating over HTMLCollection from getElementsByClassName
What's going on is an odd side effect. When you reassign className
for each element of elements
, the element gets removed from the array! (Actually, as @ user2428118 points out, elements
is an array-like object, not an array. See this thread for the difference.) This is because it no longer has the classOne
class name. When your loop exits (in the second case), the elements
array will be empty.
You could write your loop as:
while (elements.length) {
elements[0].className = 'classTwo'; // removes elements[0] from elements!
}
In your first case, by incrementing i
, you are skipping half of the (original) elements that have class classOne
.
Excellent question, by the way. Well-researched and clear.
getElementsByClassName strange behavior, skipping certain elements
You can use querySelectorAll and classList instead of the live nodelist you get with getElementsByClassName
function swapClasses() {
// Get all elements of class B
[...document.querySelectorAll(".classb")].forEach(div => {
div.classList.add("classa");
div.classList.remove("classb");
// Swap the text as well
div.textContent = "Class A";
})
}
.classa {
background-color: red;
}
.classb {
background-color: green;
}
<div class="classa">Class A</div>
<div class="classb">Class B</div>
<div class="classb">Class B</div>
<div class="classb">Class B</div>
<div class="classb">Class B</div>
<button onclick="swapClasses();">Swap class B to class A</button>
getElementsByClassName does not return a fixed answer
This is because A
is not an Array
. getElementByClassName
returns an HTMLCollection
which is live-updated due to changes in the document.
The easiest way to convert an array-like object into an array would be to do this:
var A = ...
// With ES5 code
var A_array = Array.prototype.slice.call(A);
// With ES6 code
var A_array = Array.from(A);
Or you can get NodeList
instead via querySelectorAll
, which won't live-update.
var A = document.querySelectorAll('.someclass');
getElementsByClassName is not working, but Id's work fine
document.getElementsByClassName returns a HTMLCollection
instead of a single element.
You need to write
var original = document.getElementsByClassName("duplicator")[0];
That is if you have a single element with that classname you want to manipulate.
The getElementsByClassName() method returns an array-like object of all child elements which have all of the given class names.
Read more about this here
Javascript For Loop execution on dom element
getElementsByClassName returns a live HTMLCollection object, which gets updated when you remove the class from the elements.
So one simple logic you can use is to use a while loop and see if the collection has any items, if so remove the class from the first item.
function removeClass() { var elements = document.getElementsByClassName("test"); console.log("Length " + elements.length) while (elements.length) { elements[0].setAttribute("class", ""); }}
.test { color: red;}
<span class="test" id="test1">Test1 </span><span class="test" id="test2">Test2 </span><span class="test" id="test3">Test3 </span><button onclick="removeClass()">Test</button>
HTML getElementsByClassName returns HTMLCollection with length of 0
Using getElementsByClassName()
will return all the elements with that class name in a document as a NodeList. This object represents a collection of nodes that can be accessed by index numbers, which starts in 0. In order to access the elements in the NodeList you will have to use a loop.
When you console.log(document.getElementsByClassName('gtableheader').length);
you see 0 because when you run it there is no element with class gtableheader
. You are able to see the items in the console because document.getElementsByClassName()
returns a live collection that is updated when the new elements are added.
As well, in the code you are using and the length is 0, you can use the code below to access the class name.
document.getElementsByClassName('gtableheader')[0].style.color="red";
If you want to access all the elements in the class you can use a for loop.
var x = document.getElementsByClassName('gtableheader');
for (var i = 0; i < x.length; i++) {
x[i].style.color = "red";
}
More information:
http://www.w3schools.com/jsref/met_document_getelementsbyclassname.asp
Wrapping elements while looping through HTMLCollection causes problem
You were iterating the container.children
list which you were also changing during the iterations. This messed up the iteration. You can solve this, as you mentioned yourself, by converting the container.children
to an array because then you are not iterating over the live container.children
list but over an array copy of that. This copy is still referring to the correct child elements so they are moved correctly with the appendChild()
function.
As an alternative you can use the querySelecterAll()
to retrieve all the elements you want to wrap.
const container = document.querySelector('.container');
const items = container.querySelectorAll('.container > *');
for(let i = 0; i < items.length; i++) {
const wrapper = document.createElement('div');
wrapper.classList.add('wrapper');
wrapper.appendChild(items[i]);
container.appendChild(wrapper);
}
.wrapper {
background-color: red;
}
<div class="container">
<div class="item_1">1</div>
<div class="item_2">2</div>
<div class="item_3">3</div>
<div class="item_4">4</div>
<div class="item_5">5</div>
<div class="item_6">6</div>
<div class="item_7">7</div>
<div class="item_8">8</div>
<div class="item_9">9</div>
</div>
Related Topics
Replace HTML Page With Contents Retrieved Via Ajax
How to Get the Cursor Position in a Textarea
Adding Additional Data to Select Options Using Jquery
Add Svg Element to Existing Svg Using Dom
Only Detect Click Event on Pseudo-Element
How to Pause and Resume Css3 Animation Using JavaScript
How to Select All Checkboxes With Jquery
Using Selenium to Imitate Dragging a File Onto an Upload Element
Compare Two Dates With JavaScript
Getcurrentposition() and Watchposition() Are Deprecated on Insecure Origins
How to Add a ≪Script≫ Element to the Dom and Execute Its Code
How to Re-Trigger a Webkit CSS Animation Via JavaScript
How to Prevent JavaScript Injection Attacks Within User-Generated Html
How to Include CSS and Js Files Via Https When Needed