dedaumiersmith dedaumiersmith - 3 months ago 12
Javascript Question

Why is my JavaScript for-loop skipping elements?

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!

Answer

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');
}
Comments