Reputation: 45
I'm having a difficult time trying to figure out how to iterate through an array of DOM elements. I have an array of div
s 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 div
s 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 div
s 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
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
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