I have a for
loop that runs through a set of elements, removing the 'selected'
class from each. However, it skips over every second iteration. I've found that I can get around this by adding j--
, which I guess is fine except for lengthening my code. But I wonder if someone could explain why it skips and perhaps suggest a more succinct way of writing this code? (I'm still learning the ropes and want to make sure I understand what's going on.)
var selections = document.getElementsByClassName(name + 'selected');
for (var j = 0; j < selections.length; j++) {
selections[j].classList.remove('selected');
j--; // the fix
}
// where name is a present variable
Thanks for your time!
It can consist of multiple sub-statements i.e. there can be multiple conditions. For as long as condition evaluates to true , the code written inside the while block keeps on executing. As soon as condition evaluates to false , the loop breaks.
The For Loop Expression 1 is executed (one time) before the execution of the code block. Expression 2 defines the condition for executing the code block. Expression 3 is executed (every time) after the code block has been executed.
for loop is synchronous.
This is because getElementsByClassName()
returns a live HtmlCollection
; in other words, the HtmlCollection
automatically updates, so as you remove the class "selected" from an element, that element is removed from the collection.
You can simply do;
var selections = document.getElementsByClassName(name + 'selected');
while (selections.length) {
selections[0].classList.remove('selected');
}
... instead.
Alternatively, as pointed out by Paul Roub in the comments, you can iterate in reverse;
for (var j = selections.length-1; j >= 0; j--) {
selections[j].classList.remove('selected');
}
Or, you can avoid a live HtmlCollection
completely, either by copying the collection to an array;
var selections = Array.prototype.slice.call(document.getElementsByClassName(name + 'selected'));
for (var j = 0; j < selections.length; j++) {
selections[j].classList.remove('selected');
}
... or, as pointed out by Yury Tarabanko in the comments, using querySelectorAll
instead;
var selections = document.querySelectorAll('.' + name + 'selected');
for (var j = 0; j < selections.length; j++) {
selections[j].classList.remove('selected');
}
getElementsByClassName is a live HTML collection so when you remove the class the element, it is updated. So that means what used to be in the index after it is now in the location where you removed the element.
var selections = document.getElementsByClassName('selected');
console.log("before: ", selections.length);
selections[0].classList.remove("selected");
console.log("after: ", selections.length);
<div class="selected"></div>
<div class="selected"></div>
<div class="selected"></div>
<div class="selected"></div>
<div class="selected"></div>
Looping backwards works because the items are not shifting down.
Option option is to do a while loop.
var selections = document.getElementsByClassName('selected');
while(selections.length) {
selections[0].classList.remove("selected");
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With