Reputation: 150
I want to start by saying I am fairly new to Plain JavaScript so I am sorry if it is something obvious.
I am trying to remove errors when someone resubmits the form with the following code.
let div = document.getElementsByClassName('error')
if (div.length > 0 ){
console.log(div);
console.log('Length: ' + div.length);
for (i = 0; i <= div.length; i++){
console.log('i= ' + i)
let e = div[i]
e.innerHTML = ''
e.classList.remove('error')
}
}
That works, sorta, I end up getting every other div with the error class being altered instead of all of them.
Upvotes: 1
Views: 357
Reputation: 43880
The older methods .children
, .getElementsByTagName()
, .getElementsByName()
, .getElementsByClassName()
, etc. return a Live Collection of DOM Objects. This means if any object (i.e. elements, i.e. <div>
, <span>
, etc,) in this collection (a.k.a. HTMLCollection, a.k.a. NodeList) is modified, or removed, or if a new object is added, the overall collection will change immediately. So on every loop you actually have a different array (or array-like object), therefore the results are a product of an ever changing group of values and quantities.
Use .querySelectorAll()
which returns a "static" NodeList.
With a for
loop, declare your increment var (i
) by:
declaring it outside of the for
loop as: var i = 0;
OR
declaring within the for
loop as: let i = 0;
var div = document.querySelectorAll('.error');
var qty = div.length;
for (let i = 0; i < qty; i++) {
console.log('i= ' + i);
var d = div[i];
d.innerHTML = 'GOOD';
d.classList.toggle('error', 'good');
}
.as-console-wrapper.as-console-wrapper {
transform: translateX(100%);
max-width: 250px;
height: 100%;
color: blue;
font: 400 15px/1.3 'Consolas';
}
<div class='error'>ERROR</div>
<div class='error'>ERROR</div>
<div class='error'>ERROR</div>
<div class='error'>ERROR</div>
<div class='error'>ERROR</div>
<div class='good'>GOOD</div>
<div class='error'>ERROR</div>
<div class='error'>ERROR</div>
<div class='error'>ERROR</div>
<div class='error'>ERROR</div>
Upvotes: 1
Reputation: 413717
The .getElementsByClassName()
function returns a live NodeList. That means that when you change the class on an entry, it disappears from the list. The length of the list drops by one, so your iteration skips every other entry.
One good way to do it is to just operate on the first thing in the list until the list is empty:
while (div.length) {
let e = div[0]
e.innerHTML = ''
e.classList.remove('error')
}
Upvotes: 5