javascriptfor-loopforeach

Why isn't forEach allowing me to access element properties?


Using a simple counter to iterate a collection works fine, but when I try to change it to use forEach it fails. Can someone point me in the right direction? Here's the code (code in question is commented out...first one works, second one doesn't)

function slideImage(offset = 0) {
  let i;
  let slides = document.getElementsByClassName("mySlides");
  let minCount = 1;
  let maxCount = slides.length;

  if (typeof index === "undefined") {
    index = 0;
  }

  index += offset;

  if (index > maxCount) {
    index = minCount;
  }

  if (index < minCount) {
    index = maxCount;
  }

  **// THIS PIECE OF CODE WORKS FINE (when uncommented obviously)
  //   for (i = 0; i < maxCount; i++) {
  //     slides[i].style.display = "none";
  //   }**

  **// WHEN I TRY TO USE FOREACH IT FAILS???
  // slides.forEach((c) => {
  //  c.style.display = "none";
  // });**


  slides[index - 1].style.display = "block";
}

The slides collection are divs each one containing an img .. here's a sample

<div class="mySlides fade">
  <img class="photo-one" src="/images/xxx.webp"/>
</div>
<div class="mySlides fade">
  <img class="photo-one" src="/images/xxx.webp"/>
</div>
<div class="mySlides fade">
  <img class="photo-one" src="/images/xxx.webp"/>
</div>

Solution

  • getElementsByClassName returns an HTMLCollection object, which is an array-like object that you can loop over. However it lacks methods like forEach to loop over the values in the object.

    Use the more powerful querySelectorAll() function which returns a NodeList which has the forEach method.

    let slides = document.querySelectorAll(".mySlides");
    

    Alternatively you could turn your HTMLCollection into an array with the Array.from function, but I'd recommend learning to use querySelector and querySelectorAll for finding elements.

    Array.from(slides).forEach(slide => {
      slide.style.display = "none";
    });
    

    An important difference between a HTMLCollection and a NodeList is that the HTMLCollection is a live collection which means it will change whenever you add or remove elements from the document that have the class you're querying, whereas the NodeList is a snapshot of the found elements at the time of calling.

    let slides = document.querySelectorAll(".mySlides");
    
    slides.forEach(slide => {
      console.log(slide.className);
    });
    <div class="mySlides fade">
      <img class="photo-one" src="/images/xxx.webp"/>
    </div>
    
    <div class="mySlides pulse">
      <img class="photo-one" src="/images/xxx.webp"/>
    </div>
    
    <div class="mySlides flyin">
      <img class="photo-one" src="/images/xxx.webp"/>
    </div>