Reputation: 1
I'm relatively new to JavaScript and in this program I encountered some strange behavior that I would like to understand.
Some context: resetButton
is a button to reset the elements in boxes
to their initial state. As part of this process, I clone all the elements in boxes
to remove their event listeners. Next, I would like to re-add the event listeners to the new elements. This is where the problem arises.
In the first code snippet, boxes
is defined outside the initializeBoxes
and the addEventListener
for resetButton
and it seems like I am unable to add event listeners to the elements in boxes
In the second code snippet, boxes
is defined inside each function and this code works fine. It looks like the event listeners are cleared and re-added when initalizeBoxes
is called.
I think this has to do with scope, however I thought that initalizeBoxes
's closure would capture boxes
from outside the function. This is where I can't understand what is really happening. Any insights would be greatly appreciated!
let boxes = document.querySelectorAll('.box');
let resetButton = document.getElementById('reset');
resetButton.addEventListener('click', () => {
boxes.forEach((box) => {
box.replaceWith(box.cloneNode(true));
});
initalizeBoxes();
});
function initalizeBoxes() {
boxes.forEach((box) => {
box.addEventListener('click', () => {
// do stuff
let resetButton = document.getElementById('reset');
resetButton.addEventListener('click', () => {
let boxes = document.querySelectorAll('.box');
boxes.forEach((box) => {
box.replaceWith(box.cloneNode(true));
});
initalizeBoxes();
});
function initalizeBoxes() {
let boxes = document.querySelectorAll('.box');
boxes.forEach((box) => {
box.addEventListener('click', () => {
// do stuff
Upvotes: 0
Views: 31
Reputation: 370809
In the first snippet, the boxes
variable refers to the collection of elements matching .box
that existed at the moment that line was run - let boxes = document.querySelectorAll('.box');
- so, those elements when the page was loaded. The first time the button is clicked, boxes.forEach((box) => { box.replaceWith
may properly iterate over all those elements. But then if you click the button again sometime, all elements in the boxes
variable refer to elements no longer in the document, so calling .replaceWith
on them doesn't affect anything in the current DOM.
In contrast, if you select the boxes inside the button's click listener, you'll be selecting all boxes that exist in the DOM at that point, so you'll be guaranteed to have an up-to-date collection to iterate over and replace.
Upvotes: 2