Strange Behavior When Iterating Over Htmlcollection from Getelementsbyclassname

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



Leave a reply



Submit