jtc10
jtc10

Reputation: 45

How to iterate through DOM nodelist/array

I'm having a difficult time trying to figure out how to iterate through an array of DOM elements. I have an array of divs that contains img elements. I started with a nodelist but converted it to an array. I'd like to be able to press specific buttons and have divs with certain classes disappear. The event listener is functional because upon clicking a button the first element with the specified class disappears, just not the rest of the divs with the same class name.

The relevant HTML

<!-- list items for the project gallery -->
      <ul class="gallery-list">
        <li class="gallery-list-item all-button">All</li>
        <li class="gallery-list-item indoor-button">Indoor</li>
        <li class="gallery-list-item outdoor-button">Outdoor</li>
      </ul>
      <!-- flex container for gallery pictures -->
      <div class="gallery-flex-container">
        <!-- flex items / content images -->
        <div class="gallery-flex-item show-all indoor">
          <img src="images/indoor-1.jpg" alt="indoor garden picture">
        </div>
        <div class="gallery-flex-item show-all outdoor">
          <img src="images/outdoor-1.jpg" alt="outdoor garden picture">
        </div>
        <div class="gallery-flex-item show-all indoor">
          <img src="images/indoor-2.jpg" alt="indoor garden picture">
        </div>
        <div class="gallery-flex-item show-all outdoor">
          <img src="images/outdoor-2.jpg" alt="outdoor garden picture">
        </div>
        <div class="gallery-flex-item show-all indoor">
          <img src="images/indoor-3.jpg" alt="indoor garden picture">
        </div>
        <div class="gallery-flex-item show-all outdoor">
          <img src="images/outdoor-3.jpg" alt="outdoor garden picture">
        </div>
        <div class="gallery-flex-item show-all indoor">
          <img src="images/indoor-4.jpg" alt="indoor garden picture">
        </div>
        <div class="gallery-flex-item show-all outdoor">
          <img src="images/outdoor-4.jpg" alt="outdoor garden picture">
        </div>
        <div class="gallery-flex-item show-all indoor">
          <img src="images/indoor-5.jpg" alt="indoor garden picture">
        </div>
        <div class="gallery-flex-item show-all outdoor">
          <img src="images/outdoor-5.jpg" alt="outdoor garden picture">
        </div>
        <div class="gallery-flex-item show-all indoor">
          <img src="images/indoor-6.jpg" alt="indoor garden picture">
        </div>
        <div class="gallery-flex-item show-all outdoor">
          <img src="images/outdoor-6.jpg" alt="outdoor garden picture">
        </div>
      </div>

The relevant CSS

.hide-indoor {
  display: none;
}

.hide-outdoor {
  display: none;
}

the relevant Javascript

// Script for gallery page picture toggle

let imgArray = [...document.querySelectorAll('.gallery-flex-item')];

console.log(imgArray);

var listItem = document.querySelector('.gallery-list');
var indoor = document.querySelector('.indoor');
var outdoor = document.querySelector('.outdoor');

listItem.addEventListener('click', function (e) {
  for (var i = 0; i < imgArray.length; i++) {
    if (e.target.classList.contains('all-button')) {
      indoor.classList.remove('hide-indoor');
      outdoor.classList.remove('hide-outdoor');

    } else if (e.target.classList.contains('indoor-button')) {

// Here is the section of code I tried incorporating the 'i' variable
// and it works the exact same as the other two 'if' statements.
// Only manipulating the first of elements with selected classes.

      if (imgArray[i].classList.contains('indoor')) {  
        indoor.classList.remove('hide-indoor');
      } else if (imgArray[i].classList.contains('outdoor')) {
        outdoor.classList.add('hide-outdoor');
      }

    } else if (e.target.classList.contains('outdoor-button')) {
      outdoor.classList.remove('hide-outdoor');
      indoor.classList.add('hide-indoor');
    }

  }
});

This is the first time I've tried iterating through DOM elements so I'm really not sure where I'm going wrong.

Upvotes: 1

Views: 211

Answers (2)

Tomasz Kula
Tomasz Kula

Reputation: 16837

I've simplified your code a little bit. This should get you started.

You do not need hide-outdoor and hide-indoor css classes that do the same. You can use shared hide class and apply it to different elements.

You also do not need showAll class. If the element is not hidden it will be visible.

const getEl = (selector) => document.querySelector(selector);
const getAllEls = (selector) => [...document.querySelectorAll(selector)];
const hideEl = (el) => el.classList.add('hide');
const showEl = (el) => el.classList.remove('hide');
const hideEls = (selector) => getAllEls(selector).forEach(hideEl);
const showEls = (selector) => getAllEls(selector).forEach(showEl);

const select = getEl('[data-all]');
const indoor = getEl('[data-indoor]');
const outdoor = getEl('[data-outdoor]');
const indoorEls = getAllEls('.indoor');
const outdoorEls = getAllEls('.outdoor');

select.addEventListener('click', () => {
  showEls('.indoor');
  showEls('.outdoor');
})

indoor.addEventListener('click', () => {
  showEls('.indoor');
  hideEls('.outdoor');
})

outdoor.addEventListener('click', () => {
  showEls('.outdoor');
  hideEls('.indoor');
})
.hide {
  display: none;
}
<ul class="menu">
  <li data-all>All</li>
  <li data-indoor>Indoor</li>
  <li data-outdoor="">Outdoor</li>
</ul>
<div class="gallery">
  <div class="gallery-item  indoor">
    <img src="https://via.placeholder.com/50x50" alt="indoor garden picture">
  </div>
  <div class="gallery-item  outdoor">
    <img src="https://via.placeholder.com/150x150" alt="outdoor garden picture">
  </div>
</div>

Upvotes: 0

xuhaib
xuhaib

Reputation: 768

The event listener is functional because upon clicking a button the first element with the specified class disappears, just not the rest of the divs with the same class name.

Use querySelectorAll in place of querySelector.

querySelectorAll will return list of all the matching element nodes unlike querySelector which returns only the first matching element node.

For Reference: Mozilla documentation

Upvotes: 1

Related Questions