Currently developing a shop-like web page for a school task and I am running into a problem where the eventListeners seem to not be applied to the button elements.
I’m running a forEach
loop on an array containing data on the items that you can buy in the shop. Basically, every object
in array
> print article with object data to the container, along with adding an eventListener to the button which is supposed to pass along data to a handleBuyEvent function to further check if the user has enough money/resources etc. etc.
The issue is when the articles are printed to the web page (no errors in the console) nothing happens when I click the buttons, and when I inspect the button elements, under eventListeners it says no listeners…
import WarriorsModule from "./modules/warriorsModule.js";
import InventoryModule from "./modules/inventoryModule.js";
const warriors = WarriorsModule().getAll(); // returns array with objects containing data
const inventory = InventoryModule();
const warriorsContainer = document.querySelector("#warriorsContainer");
const ironResources = document.querySelector("#ironResource");
const coinResources = document.querySelector("#coinResource");
const woodResources = document.querySelector("#woodResource");
// Updates current resources on screen.
const updateResources = () => {
ironResources.innerHTML = inventory.getIronBalance();
coinResources.innerHTML = inventory.getCoinBalance();
woodResources.innerHTML = inventory.getWoodBalance();
}
updateResources();
const handleBuyEvent = (category, price, img) => {
if (inventory.getCoinBalance() >= price) {
inventory.addToArmy({
category: `${category}`,
price: `${price}`,
img: `${img}`
});
inventory.removeCoins(price);
updateResources();
} else {
alert(
`You are missing: ${
(price - inventory.getCoinBalance())
} coins to buy this unit.`
);
}
};
let handleClickEvent = (category, price, img) => {
handleBuyEvent(category, price, img);
};
const printWarriors = () => {
// This id is being used to identify the different buttons and containers in each article
let id = 0;
warriors.forEach((object) => {
const buttonContainer = document.createElement("div");
buttonContainer.setAttribute("id", `buttonContainer${id}`);
// Create the button element and set up its properties
const buttonElement = document.createElement("button");
buttonElement.setAttribute("id", `buyButton${id}`);
buttonElement.setAttribute("class", "btn btn-success m-4");
buttonElement.innerHTML = `
Buy ${object.category} Warrior - ${object.price}
`;
const category = object.category;
const price = object.price;
const img = object.img;
buttonElement.addEventListener('click', () => {
handleClickEvent(category, price, img);
});
buttonContainer.appendChild(buttonElement);
// Prints article to website
warriorsContainer.innerHTML += `
<article class="col-sm-12 col-md-6 col-lg-4">
<div class="warriorArticle shadow rounded d-flex flex-column align-items-center">
<h3 class="m-4 fs-2" >${object.category}</h3>
<div class="row">
<img class="categoryImage" src="${object.img}" alt="${object.category}-img"/>
</div>
${buttonContainer.outerHTML}
</div>
</article>
`;
// Increments the ID so that on the next iteration the ID set is different.
id += 1;
});
};
printWarriors();
I have tried asking chatGPT 100 times but it doesn’t seem to find the issue. I read through the code to see if there was a mistake somewhere regarding getting the ID for certain elements in case that is why it was never applied.
At this point, I have no idea why it won’t work and at the same time gives no errors AND everything else is printed and shown as expected.
2
Answers
It’s because you added
buttonContainer
usingwarriorsContainer.innerHTML
andbuttonContainer.outerHTML
. If you want to add the actual button along with its event listeners to the DOM, you need to truly insert the element using something likeappendChild()
orinsertAdjacentElement()
.Your issue arises from the order in which you are executing operations. When you create the
buttonElement
and attach an event listener to it, the element exists in memory but has not been attached to theDOM
yet. However, when you later append the entirearticle
towarriorsContainer
usinginnerHTML
, it does not copy the event listeners.Here’s a breakdown of my understanding of the task:
buttonElement
and attach an event listener to it.buttonContainer
.buttonContainer
to the warriorsContainer using innerHTML +=.That said, using
innerHTML +=
does not copy over the event listeners from the in-memory version of the element. To resolve this, you need to attach the created DOM nodes directly to the warriorsContainer without converting them to strings with innerHTML.Here’s a revised version of the
printWarriors
function to fix this:By using the
DOM
methods(createElement, appendChild, etc.)
and not usinginnerHTML
for appending dynamic content, the event listeners attached to elements remain intact.