1

Here's the problem:

Change the 3 divs below (they're not visible) to be 50x50 red squares

<div class="empty"></div>
<div class="empty"></div>
<div class="empty"></div>

Built in class that we are changing to:

<style media="screen">
  .red{
    width:50px;
    height:50px;
    background:red;
  }

This solution only acts on the first and last div, leaving the middle out:

let boxes = document.getElementsByClassName('empty');

function addThree(boxes) {
  for (let i = 0; i < boxes.length; i++) {
    boxes[i].className = 'red';
 }
}
addThree(boxes);

Solution that does work on all three divs;

let boxes = document.getElementsByClassName('empty');

function addThree(boxes) {
  for (let i = 0; i < boxes.length; i++) {
    boxes[i].classList.add('red');
 }
}
addThree(boxes);

Not really sure what the difference here is, if anyone could give a explanation that would be awesome!

  • Assigning to `className` overwrites the entire `class` attribute, removing the `empty` class. This mutates `boxes`, reducing its length by one. – Sebastian Simon Nov 13 '17 at 21:52

2 Answers2

2

The problem is that document.getElementsByClassName('empty') returns live HTMLCollection. It means the it automatically updates itself when DOM changes. So when you assign (you wipe away previous class empty)

boxes[0].className = 'red';

to the first element that has been empty before, the collection boxes is no longer 3 element, but now only 2.

On the other hand, boxes[i].classList.add('red') won't affect boxes collection length because red class gets added to element (so it becomes empty red - still empty), not overwrites all previous classes.

dfsq
  • 191,768
  • 25
  • 236
  • 258
  • Could you add in how the change in length co-incides with the loop-counter being `i=1`, and the next loop condition being `1 < 1`, hence failing? That was my "whoah" moment – Oliver Baumann Nov 13 '17 at 22:02
  • 1
    @OliverBaumann This is what happens. Before loop `boxes` is a collection of 3 HTML elements. `i=0, i<3`: `boxes[0]` gets new class `red` => `boxes` becomes collection of 2 HTML elements. Next iteration. `i=1, i<2`: `boxes[1]` gets class red. This is the box that previously was #3 (boxes[2]). So `boxes[1]` (from iteration i=0) or `boxes[0]` from iteration i=1 was skipped. – dfsq Nov 13 '17 at 22:10
  • yup, thought you might want to edit the answer and include that in the explanation for clarity's sake, but now it's here and that's fine too :) – Oliver Baumann Nov 13 '17 at 22:15
0

You are CHANGING the class on each element mid-loop. So once you've changed the first class, your boxes array shortens in length, and skips the first element.

You either want to ADD the class 'red' or if you want to change it, first push the divs into a different array and iterate over that

MorganIsBatman
  • 1,000
  • 8
  • 13