- 11.1 Prepping the Gallery
- 11.2 Changing the Gallery Image
- 11.3 Setting an Image as Current
- 11.4 Changing the Image Info
- 11.5 Conclusion
11.4 Changing the Image Info
Our final task is to update the image information (title and description) in the third column of our gallery. Doing this doesn’t actually require anything we haven’t seen before—we just have to put things we already know together in a slightly new way, making this an excellent way to end the tutorial.
The sequence we’ll follow is simple:
Find the DOM elements for the image title and description.
Replace the contents with the corresponding data from the clicked image.
To find the necessary DOM elements, we first observe that they are both inside the div with CSS id gallery-info:
<div class="col col-aside gallery-info" id="gallery-info"> <h3 class="title">Pacific Sunset</h3> <p class="description">A sunset over the Pacific Ocean.</p> </div>
Inside that div, both are the first (and only) elements with the title and description classes, respectively, which means we can select them as follows:
let galleryInfo = document.querySelector("#gallery-info"); let title = galleryInfo.querySelector(".title"); let description = galleryInfo.querySelector(".description");
Note that I’ve added extra spaces to line up the equals signs, which is a nice (though not strictly necessary) code formatting practice (Box 2.3).
We can get the corresponding values for the clicked image using the dataset variable introduced in Section 11.2:
thumbnail.dataset.title
for the title and
thumbnail.dataset.description
for the description.
The final piece of the puzzle is the innerHTML property we first saw in Section 9.3, which lets us directly update the inner HTML of a DOM element:
title.innerHTML = thumbnail.dataset.title; description.innerHTML = thumbnail.dataset.description;
Putting everything together gives the final version of the activateGallery function, shown in Listing 11.8.
Listing 11.8: Updating the image title and description on click.
js/gallery.js
// Activates the image gallery. // The main task is to attach an event listener to each image in the gallery // and respond appropriately on click. function activateGallery() { let thumbnails = document.querySelectorAll("#gallery-thumbs > div > img"); let mainImage = document.querySelector("#gallery-photo img"); // Image info to be updated let galleryInfo = document.querySelector("#gallery-info"); let title = galleryInfo.querySelector(".title"); let description = galleryInfo.querySelector(".description"); thumbnails.forEach(function(thumbnail) { thumbnail.addEventListener("click", function() { // Set clicked image as display image. let newImageSrc = thumbnail.dataset.largeVersion; mainImage.setAttribute("src", newImageSrc); // Change which image is current. document.querySelector(".current").classList.remove("current"); thumbnail.parentNode.classList.add("current"); // Update image info. title.innerHTML = thumbnail.dataset.title; description.innerHTML = thumbnail.dataset.description; }); }); }
Our final change involves syncing up the three columns for new visitors, so that the first column (current image indicator), second column (main image), and third column (image information) all match. This just involves updating the gallery index HTML as in Listing 11.9.
Listing 11.9: All three columns synced.
gallery/index.html
--- layout: default title: Gallery for Learn Enough JavaScript to Be Dangerous --- <div class="gallery col-three"> <div class="col col-nav gallery-thumbs" id="gallery-thumbs"> <div class="current"> <img src="/images/small/beach.jpg" alt="Venice Beach" data-large-version="/images/large/beach.jpg" data-title="Venice Beach" data-description="An overhead shot of Venice Beach, California."> </div> . . . </div> <div class="col col-content"> <div class="gallery-photo" id="gallery-photo"> <img src="/images/large/beach.jpg" alt="Venice Beach"> </div> </div> <div class="col col-aside gallery-info" id="gallery-info"> <h3 class="title">Venice Beach</h3> <p class="description">An overhead shot of Venice Beach, California.</p> </div> </div>
Now all three of our columns agree, whether it’s the Venice Beach pic that greets new visitors (Figure 11.14), a friendly sea turtle (Figure 11.15), Walt Disney Concert Hall in downtown Los Angeles (Figure 11.16), or the Flavian Amphitheater (Colosseum) in Rome (Figure 11.17).
Figure 11.14: An overhead shot of Venice Beach, California.
Figure 11.15: A friendly sea turtle.
Figure 11.16: Walt Disney Concert Hall in downtown Los Angeles.
Figure 11.17: The Flavian Amphitheater (Colosseum) in Rome.
11.4.1 Deploying
Because all the necessary files—including all the JavaScript—are completely local to our project (unlike some of the NPM modules in previous chapters), we can deploy our app to GitHub Pages with a simple git push:
$ git add -A $ git commit -m "Finish the JavaScript gallery" $ git push
Visiting the gallery at <username>.github.io and clicking on an image confirms it: We’ve deployed our dynamic JavaScript application to the live Web (Figure 11.18)! (To learn how to host a GitHub Pages site using a custom domain instead of a github.io subdomain, see the free tutorial Learn Enough Custom Domains to Be Dangerous (https://www.learnenough.com/custom-domains).)
Figure 11.18: Our JavaScript gallery app on the live Web.
11.4.2 Exercise
When clicking on a new thumbnail image on the live site (Figure 11.18), you might notice a slight delay before the main image appears in the center. This is because, unlike the thumbnails, the large versions haven’t been downloaded yet.
It’s a common practice to prevent this small but annoying delay by preloading the images in the background to put them into the browser cache—a task we can accomplish with JavaScript. The trick is to create a new Image object (javascript image object) and assign it the src of the large image corresponding to each thumbnail. This forces the browser to download all the large images before the page is even loaded.
By filling in the code in Listing 11.10 and deploying the result, confirm that image preloading works, and that the resulting image swapping is snappy and responsive. (Note that we’ve hoisted newImageSrc out of the listener, which is a big hint about what to use to replace FILL_IN.)
Listing 11.10: Preloading large versions.
js/gallery.js
// Activates the image gallery. // The main task is to attach an event listener to each image in the gallery // and respond appropriately on click. function activateGallery() { let thumbnails = document.querySelectorAll("#gallery-thumbs > div > img"); let mainImage = document.querySelector("#gallery-photo img"); thumbnails.forEach(function(thumbnail) { // Preload large images. let newImageSrc = thumbnail.dataset.largeVersion; let largeVersion = new Image(); largeVersion.src = FILL_IN; thumbnail.addEventListener("click", function() { // Set clicked image as display image. mainImage.setAttribute("src", newImageSrc); // Change which image is current. document.querySelector(".current").classList.remove("current"); thumbnail.parentNode.classList.add("current"); // Update image info. let galleryInfo = document.querySelector("#gallery-info"); let title = galleryInfo.querySelector(".title"); let description = galleryInfo.querySelector(".description"); title.innerHTML = thumbnail.dataset.title; description.innerHTML = thumbnail.dataset.description; }); }); }