Hello!
first, I know the question title seems like a duplicate but, it’s not.
I’m a beginner at Javascript and I’m trying to build a portfolio section that shows a couple of projects, if you click on an icon it will show you the project’s picture in a bigger way. Anyway I wrote a couple of js lines but, I keep getting this error:
Uncaught TypeError: Cannot read properties of undefined (reading 'classList')
at changeImage (index.js:168:19)
at HTMLSpanElement.<anonymous> (index.js:139:9)
The first image is showing and nothing wrong with it, but the other pictures, show it in a strange order and some of the pictures don’t even show!
I tried several solutions including getting the items using getElementByClassName and so on.
If you can help me I would appreciate it and tell me how it can be done!
HTML:
<section class="portfolio section" id="portfolio">
<div class="modal">
<div class="modal-overlay"></div>
<div class="slider-wrap">
<div class="prev-btn navigation">
<i class="uil uil-angle-left-b"></i>
</div>
<div class="images">
<img class="showImage" src="./assets/images/port1.jpg" alt="">
<img src="./assets/images/port2.png" alt="">
<img src="./assets/images/port3.jpg" alt="">
<img src="./assets/images/port4.png" alt="">
<img src="./assets/images/port5.png" alt="">
<img src="./assets/images/port6.jpg" alt="">
</div>
<div class="next-btn navigation">
<i class="uil uil-angle-right-b"></i>
</div>
</div>
</div>
<div class="container">
<div class="portfolio-header">
<div class="portfolio-title">
<h3 class="sub-heading">Portfolio</h3>
<h1 class="heading">Latest projects</h1>
</div>
<div class="filter-btns">
<button class="filter-btn" data-filter="all">All</button>
<button class="filter-btn" data-filter=".product">Product</button>
<button class="filter-btn" data-filter=".interaction">Interacting</button>
<button class="filter-btn" data-filter=".webapps">Web apps</button>
</div>
</div>
<div class="portfolio-gallery">
<div class="mix prt-card interaction">
<div class="prt-image">
<img src="./assets/images/port1.jpg">
<div class="prt-overlay">
<span class="prt-icon zoom-icon" style="--i: 0s">
<i class="uil uil-search-plus"></i>
</span>
<a href="#" class="prt-icon zoom-icon" style="--i: .15s">
<i class="uil uil-link"></i>
</a>
</div>
</div>
<div class="prt-desc">
<h3>Olido interaction</h3>
<a href="#" class="btn secondary-btn sm">Read more</a>
</div>
</div>
<div class="mix prt-card webapps">
<div class="prt-image">
<img src="./assets/images/port2.png">
<div class="prt-overlay">
<span class="prt-icon zoom-icon" style="--i: 0s">
<i class="uil uil-search-plus"></i>
</span>
<a href="#" class="prt-icon zoom-icon" style="--i: .15s">
<i class="uil uil-link"></i>
</a>
</div>
</div>
<div class="prt-desc">
<h3>Olido interaction</h3>
<a href="#" class="btn secondary-btn sm">Read more</a>
</div>
</div>
<div class="mix prt-card webapps">
<div class="prt-image">
<img src="./assets/images/port3.jpg">
<div class="prt-overlay">
<span class="prt-icon zoom-icon" style="--i: 0s">
<i class="uil uil-search-plus"></i>
</span>
<a href="#" class="prt-icon zoom-icon" style="--i: .15s">
<i class="uil uil-link"></i>
</a>
</div>
</div>
<div class="prt-desc">
<h3>Olido interaction</h3>
<a href="#" class="btn secondary-btn sm">Read more</a>
</div>
</div>
<div class="mix prt-card product">
<div class="prt-image">
<img src="./assets/images/port4.png">
<div class="prt-overlay">
<span class="prt-icon zoom-icon" style="--i: 0s">
<i class="uil uil-search-plus"></i>
</span>
<a href="#" class="prt-icon zoom-icon" style="--i: .15s">
<i class="uil uil-link"></i>
</a>
</div>
</div>
<div class="prt-desc">
<h3>Olido interaction</h3>
<a href="#" class="btn secondary-btn sm">Read more</a>
</div>
</div>
<div class="mix prt-card interaction">
<div class="prt-image">
<img src="./assets/images/port5.png">
<div class="prt-overlay">
<span class="prt-icon zoom-icon" style="--i: 0s">
<i class="uil uil-search-plus"></i>
</span>
<a href="#" class="prt-icon zoom-icon" style="--i: .15s">
<i class="uil uil-link"></i>
</a>
</div>
</div>
<div class="prt-desc">
<h3>Olido interaction</h3>
<a href="#" class="btn secondary-btn sm">Read more</a>
</div>
</div>
<div class="mix prt-card webapps">
<div class="prt-image">
<img src="./assets/images/port6.jpg">
<div class="prt-overlay">
<span class="prt-icon zoom-icon" style="--i: 0s">
<i class="uil uil-search-plus"></i>
</span>
<a href="#" class="prt-icon zoom-icon" style="--i: .15s">
<i class="uil uil-link"></i>
</a>
</div>
</div>
<div class="prt-desc">
<h3>Olido interaction</h3>
<a href="#" class="btn secondary-btn sm">Read more</a>
</div>
</div>
</div>
</div>
</section>
And here is the Javascript code:
const prt_section = document.querySelector(".portfolio");
const zoom_icon = document.querySelectorAll(".zoom-icon");
const modal_overlay = document.querySelector('.modal-overlay');
const images = document.querySelectorAll(".images img");
let currentIndex = 0;
zoom_icon.forEach((icn, i) =>
icn.addEventListener("click", () => {
prt_section.classList.add("open");
document.body.classList.add("stopScrolling");
currentIndex = i;
changeImage(currentIndex);
})
);
modal_overlay.addEventListener("click", () => {
prt_section.classList.remove("open");
document.body.classList.remove("stopScrolling");
});
function changeImage(index) {
images.forEach((img) => img.classList.remove("showImage"));
images[index].classList.add("showImage");
}
NOTE: When I navigate throughout the images with the mixer there is nothing wrong and it’s showing me all the images in the correct order.
Here is the mixer js code if you’re interested:
const prev_btn = document.querySelector(".prev-btn");
const next_btn = document.querySelector(".next-btn");
let mixer = mixitup(".portfolio-gallery", {
selectors: {
target: ".prt-card",
},
animation: {
duration: 500,
},
});
prev_btn.addEventListener("click", () => {
if (currentIndex === 0) {
currentIndex = 5; //NOTE: (5) is the number of the last image.
} else {
currentIndex--;
}
changeImage(currentIndex);
});
next_btn.addEventListener("click", () => {
if (currentIndex === 5) {
currentIndex = 0;
} else {
currentIndex++;
}
changeImage(currentIndex);
});
