Unless the buttons are being created dynamically, the timeout doesn’t really help much. And if the buttons are being created dynamically, there is a better way to attach that listener.
Here’s a link to a working repl of your code:
I’ve removed the setTimeout, as it doesn’t actually help. And I did change one thing: some browsers won’t allow you to do a
for loop over a list selected by
querySelectorAll (it’s not an actual array, it’s an “array-like object”). So, to bypass that, I wrapped the querySelectorAll call in an array:
const modBtn = [...document.querySelectorAll('.appuiBtn')];
That forces it to be an array, and will be acceptable to all modern browsers.
Now, in the event that you’re dynamically creating these
.appuiBtn elements, adding an event listener like this will likely continue to fail. Instead, attach the listener at a static parent element. For example, if each table row is dynamic, but the table body itself is static, add the listener there:
const container = document.querySelector("#tableau");
* Now, the table body will listen for clicks *in any of its
* how does that help us? We can simply check if the
* clicked element is one we want to act on, and if so, we
* do stuff.
// Well gee! It was one of our buttons! Let's do something!
// We already have a function you're using, let's simply pass
// our event object straight to that. Boom done.
So, in the above code, we listen at the nearest static container element. But the
Event object (read more about that here), which is passed in our
addEventListener, contains a reference to the element that was actually clicked (in the
event.target). We can check if the target is of our desired class with
event.target.classList.contains("<something>"), and if so, we can do our custom event handler for that!
The advantage of this approach is that, with dynamic elements, we can’t reliably include or remove event handlers. Doing this, we bypass the issue.
Hope that helps!