Build a Lightbox Viewer: General button question

Hello,

Happily plugging away with this one and trying to understand what’s (not) happening in my code.

Rather than an event listener for the three thumbnail buttons, I have a ‘for’ loop that adds the listener to all three at once. I then need to somehow capture the id of the button that has been pressed, but I can’d find a way of doing it. Any attempt to access an id or value from button[i] results in ‘undefined’.

Is it possible to do this within the single looped eventlistener method, or is it going to be easier just to add a different listener to each button, without using the loop?

(Also, apololgies, my first two codeblocks won’t display properly for some reason?)

Thanks!

/* file: Lightbox.html*/

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Lightbox Viewer</title>
    <link rel = "stylesheet" href = "styles.css">
  </head>
  <body>
  <h1>Click on an image below:</h1>
  
  <div class = "gallery">
	<button class = "button" value = "stone"><img id = "stonethumb" src = "https://cdn.freecodecamp.org/curriculum/labs/stonehenge-thumbnail.jpg"></button>
	<button class = "button"><img id = "stormthumb" src = "https://cdn.freecodecamp.org/curriculum/labs/storm-thumbnail.jpg"></button>
	<button class = "button"><img id = "treesthumb" src = "https://cdn.freecodecamp.org/curriculum/labs/trees-thumbnail.jpg"></button>
	
    <div class = "lightbox off"></div>
	  
    </div>
    <div class = "offbtn"><button class = "turnoff off">OFF</button></div>
  
  </body>
    <script src = "script.js"></script> 
</html>

/* file: styles.css*/

:root{
background-color: lavender; 
font-family: helvetica, sans-serif; 
}

h1{ 
text-align: center; 
}

.gallery{
border: 2px black solid; 
height: 50vh; 
width: 75vw; 
display: grid;
align-items: center;
justify-content: center;
grid-auto-flow: column;
margin: auto; 
padding: 25px;
z-index: -1;
}

img{
margin: auto;
width: 300px; 
height: 100px; 
max-width: 90%; 
max-height: auto; 
padding: 5px; 
object-fit: fill; 
}

button{
border: 0;
background-color: transparent;
transition: 0.4s ease-in-out; 
}

button:hover{
scale: 120%;
}

.lightbox{
background-color: black; 
opacity: 60%; 
height: 50vh; 
width: 75vw; 
position: absolute; 
}

.lightbox.off{
display: none; 

}

.offbtn {
width: 100px; 
height: 100px; 
margin: auto; 
padding: 20px; 
}

.turnoff{
border: 2px black solid; 
padding: 20px; 
font-weight: bold; 
background-color: white;
transition: none; 
scale: 100%;
}

.turnoff:hover{
background-color: gray;
scale: 105%;
}

.turnoff:active{
background-color: gray;
scale: 95%;
}

.turnoff.off{
display: none; 
}

/* file: script.js */

const button = document.getElementsByClassName("button"); 
const lightbox = document.querySelector(".lightbox");
const offbtn = document.querySelector(".turnoff");




for (i = 0; i < button.length; i++){
button[i].addEventListener("click", () => {
boxOn(); 
});
};

function boxOn(){
	lightbox.classList.remove("off");
	offbtn.classList.remove("off"); 
	buttonFunc(); 
return; 
};

function boxOff(){
lightbox.classList.add("off");
offbtn.classList.add("off");
}

function buttonFunc(){
offbtn.addEventListener("click", ()=> {
boxOff();
});
};

Your <button> elements don’t have an id, they only have a class attribute.

If you try to access the value attribute, only the first button will return a value ("stone").

Thanks,

Yeah sorry, I was aware and saw that after posting.

The issue is the same even after adding id’s or values. I add a value to each button and then try this:

for (i = 0; i < button.length; i++){
button[i].addEventListener("click", () => {
let clicked = button[i].value; 
console.log(clicked); 
boxOn(); 
});
};

I get: TypeError: button[i] is undefined

What I imagine is happening is that button[i] is cleared once the click function is triggered?

Is there a way to capture the id/value of the button that’s been clicked in a loop like this?

Edit:
I was being totally stupid!! I simply hadn’t declared i as a variable!! D’oh!!

if you add an argument to your callback for the addEventListener function (usually e or event are used), the clicked element is e.target

1 Like

You can also use this as long as your callbacks are normal functions (i.e. not arrow functions).

And just to be clear, the .id property is on the click target e.target.id or this.id

Examples
document.querySelectorAll("button").forEach((btn) => {
  btn.addEventListener("click", function () {
    console.log("Element:", this);
    console.log("Element text:", this.innerText);
    console.log("Element id:", this.id);
  });
});
document.querySelectorAll("button").forEach((btn) => {
  btn.addEventListener("click", (e) => {
    console.log("Element:", e.target);
    console.log("Element text:", e.target.innerText);
    console.log("Element id:", e.target.id);
  });
});
1 Like

Thanks guys. Really helpful :slight_smile:

As an aside, with the callback function, how do I remove the event?

If with a normal named funtion you would do:

removeEventListener("click", function)

How does this work with the empty arrow function?

("click", ()=>{code})

it probably doesn’t work with anonymouse functions