I have multiple buttons. When clicking on one of the buttons, I want to add a small checkmark after the button text and remove it after 1 second with a timeout.
This works fine as long as I don’t click 2 or more buttons within the 1 second time frame.
To see the issue, just click 2 or 3 buttons within 1 second. The checkmark will only be removed on the last clicked button.
How can I solve this issue? I would think the timeout could be bound to the clicked element but I don’t know how to achieve that.
// Get all .copy-clip buttons
let copyEls = document.querySelectorAll('.copy-clip');
let timeoutHandle;
// For each button
copyEls.forEach(el => {
// Register click event listener
el.addEventListener('click', (e) => {
// Reset the inner HTML to avoid multiple copy checkmarks
e.target.innerHTML = 'Copy';
// Reset timeout
window.clearTimeout(timeoutHandle);
// Add copy checkmark in button inner HTML
e.target.innerHTML += '<span class="copy-check"> ✓</span>';
// Remove copy checkmark after 1 sec
timeoutHandle = setTimeout(function() {
e.target.innerHTML = 'Copy'
}, 1000);
})
})
button {
margin-bottom: 5px;
}
<button class="copy-clip">Copy</button><br>
<button class="copy-clip">Copy</button><br>
<button class="copy-clip">Copy</button><br>
3
Answers
Because there’s only one
timeoutHandle
. So as soon as a second value is assigned to it, the previous value is lost. Instead, create a new one in each iteration of the loop. For example:Move
let timeoutHandle;
into the loopSimple, delegated and does not add/remove DOM elements
Storing the timeout handle in the button