JavaScript
Large image view
Show the large image when a card is clicked using click event and event delegation.
Clicks with event delegation
Instead of adding a listener to each image, we add a single click listener to the gallery container. This pattern is called event delegation.
The clicked element is given by event.target. If event.target.tagName === 'IMG', an image was clicked; we open the large view with that image's source.
This way, even if images are added to the grid later, the listener doesn't need to be set up again.
The large view with classList
For the large view we'll use a modal div. It starts hidden with the hidden class, so it's not visible on screen. When a card is clicked we do two things:
- set the large image source with
modalImg.src = event.target.src - open the view with
modal.classList.remove('hidden')
To close it, we add a click listener to the modal itself; when clicked, modal.classList.add('hidden') hides it again.
Exercise Add the large view listeners
Continue on top of the previous lesson's solution. A modal div and a modalImg have been added to the skeleton; you'll write the click listeners. Add gallery.addEventListener('click', function(event) {...}); inside it, if event.target.tagName === 'IMG', set modalImg.src = event.target.src and call modal.classList.remove('hidden'). For closing, add modal.addEventListener('click', function() {...}) and inside it call modal.classList.add('hidden').
Show example solution
Start with gallery.addEventListener('click', function(event) {...}); inside, if (event.target.tagName === 'IMG') set modalImg.src = event.target.src and call modal.classList.remove('hidden'). Close with modal.addEventListener('click', function() { modal.classList.add('hidden'); }).
Example solution:
// Gallery application
const app = document.getElementById("app");
const title = document.createElement("h1");
title.textContent = "Gallery";
app.appendChild(title);
const gallery = document.createElement("div");
gallery.className = "gallery";
app.appendChild(gallery);
const images = [
{ url: "https://picsum.photos/id/1/200/200", title: "Mountain view", author: "Alex" },
{ url: "https://picsum.photos/id/2/200/200", title: "City streets", author: "Mark" },
{ url: "https://picsum.photos/id/3/200/200", title: "Lakeside", author: "Zoe" }
];
async function fetchImages(url) {
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error("HTTP " + response.status);
}
return await response.text();
} catch (error) {
console.log(error.message);
}
}
function renderGrid(images) {
images.forEach(function(image) {
const card = document.createElement("figure");
const img = document.createElement("img");
const caption = document.createElement("figcaption");
img.src = image.url;
img.alt = image.title;
caption.textContent = image.author;
card.appendChild(img);
card.appendChild(caption);
gallery.appendChild(card);
});
}
// Large view modal
const modal = document.createElement("div");
modal.classList.add("hidden");
const modalImg = document.createElement("img");
app.appendChild(modal);
modal.appendChild(modalImg);
gallery.addEventListener("click", function(event) {
if (event.target.tagName === "IMG") {
modalImg.src = event.target.src;
modal.classList.remove("hidden");
}
});
modal.addEventListener("click", function() {
modal.classList.add("hidden");
});
Test yourself
-
Why is event delegation useful?
gallery.addEventListener('click', function(event) {
// ...
});
- It runs more slowly
- It only works on form elements
- It needs a separate listener per item
- One listener watches all children
Show answer
One listener watches all children — Correct! A single listener on the parent watches all children.
-
Get the clicked element
const target = ____;
Show answer
const target = event.target;
-
Match the event concepts
- event.target
- Clicked element
- tagName
- Element type
- classList.remove
- Removing a class
- classList.add
- Adding a class
- addEventListener
- Listening for events
Next lesson: Project final - Gallery