Solved! See solution at bottom. This is different than every other "removeEventListener not working using bind()" post out there. I've read them all. This one is a different situation with a different solution. I hope this helps someone who needs it! :)
I have read through every "removeEventListener doesn't work" post I can find, but I seem to be using the method correctly. I cannot figure out what I'm doing wrong here. I have multiple delete buttons on a page. For each one, I have an event listener set up for clicks. If one is clicked, a dialog is shown and the code block then sets up two event listeners, one on the document
object for keydown
of Escape
key, to close the dialog, and one on the document.body
object to shake the dialog if the user clicks outside the dialog.
In a main.js
file, I have:
const listsContainerlistNameDeleteButton = document.querySelectorAll('.to-do-lists-list-delete-button');
listsContainerlistNameDeleteButton.forEach((item)=>{
item.addEventListener('click', listsContainerlistNameDeleteButtonClickEventHandler);
});
In a separate eventHandlers.js
file, I have:
function listsContainerlistNameDeleteButtonEscapeKeydownEventHandler(event){
const index = this.value;
if(event.key==='Escape'){
// ...
document.removeEventListener('keydown', listsContainerlistNameDeleteButtonEscapeKeydownEventHandler.bind(this), false);
document.body.removeEventListener('click', listsContainerlistNameDeleteButtonClicksOutsideDeleteConfirmationContainerEventHandler.bind(this), false);
// ...
}else if(event.key==='Enter'){
// ...
};
};
function listsContainerlistNameDeleteButtonClicksOutsideDeleteConfirmationContainerEventHandler(event){
// ...
};
function listsContainerlistNameDeleteButtonClickEventHandler(event){
const index = this.value;
// ...
document.addEventListener('keydown', listsContainerlistNameDeleteButtonEscapeKeydownEventHandler.bind(this), false);
document.body.addEventListener('click', listsContainerlistNameDeleteButtonClicksOutsideDeleteConfirmationContainerEventHandler.bind(this), false);
// ...
};
No matter what I try, I cannot get the event listeners to remove when the Escape
key is pressed. I have used a console.log
statement to verify that the .removeEventListener
call is firing. I have made sure the event listener function is stored as a variable. I have made sure I am calling the same variable name in the addEventListener
and removeEventListener
calls. It seems like everything is matching correctly.
Can anyone tell me what is wrong with my code?
EDIT: My first time posting this question, I was told I needed to only bind the function once. I am not exactly sure what that means, but I have now tried:
function listsContainerlistNameDeleteButtonEscapeKeydownEventHandler(event){
const index = this.value;
if(event.key==='Escape'){
removeInertAttribute(topBarContainer);
listsContainerlistNameTextInput.forEach((item)=>{
removeInertAttribute(item);
});
listsContainerlistNameCategoryInput.forEach((item)=>{
removeInertAttribute(item);
});
listsContainerlistNameViewButton.forEach((item)=>{
removeInertAttribute(item);
});
listsContainerlistNameEditButton.forEach((item)=>{
removeInertAttribute(item);
});
listsContainerlistNameDeleteButton.forEach((item)=>{
removeInertAttribute(item);
});
removeInertAttribute(newListEntryFormContainer);
document.removeEventListener('keydown', listsContainerlistNameDeleteButtonEscapeKeydownEventHandler.bind(this), false);
// escapeListener.abort();
document.body.removeEventListener('click', listsContainerlistNameDeleteButtonClicksOutsideDeleteConfirmationContainerEventHandler.bind(this), false);
listsContainerlistNameDeleteConfirmationContainer[index].classList.remove('to-do-lists-delete-confirmation-container-show');
listsContainerlistNameDeleteConfirmationContainerUnder400px[index].classList.remove('to-do-lists-delete-confirmation-container-show');
setTimeout(()=>{
toggleCssDisplayPropertyBetweenNoneAndBlock(listsContainerlistNameDeleteConfirmationContainerBackdrop[index]);
console.log('toggle for regular ran');
toggleCssDisplayPropertyBetweenNoneAndBlock(listsContainerlistNameDeleteConfirmationContainerBackdropUnder400px[index]);
console.log('toggle for under 400px ran');
}, 250);
}else if(event.key==='Enter'){
listsContainerlistNameDeleteForm[index].submit();
};
}.bind(this);
function listsContainerlistNameDeleteButtonClicksOutsideDeleteConfirmationContainerEventHandler(event){
const clickTarget = event.explicitOriginalTarget;
const index = this.value;
if(!listsContainerlistNameDeleteConfirmationContainer[index].contains(clickTarget)) {
shakeElement(listsContainerlistNameDeleteConfirmationContainer[index]);
};
if(!listsContainerlistNameDeleteConfirmationContainerUnder400px[index].contains(clickTarget)) {
shakeElement(listsContainerlistNameDeleteConfirmationContainerUnder400px[index]);
};
}.bind(this);
however, I now get a syntax error.
I am really not sure what to do. I am very new to programming and this is going over my head completely. If someone could be kind enough to show me what I need to change, instead of just offering some short, cryptic blurb that is only meaningful to someone who wouldn't be having this problem in the first place, I would greatly appreciate it.
Solution:
My first problem, as pointed out cryptically, was that I was binding the event listener function during the .addEventListener call, which was causing a different instance of each function each time it was used. What I need to do was use the bind on the given function declaration instead of within the .addEventListener method.
However, if I tried to add .bind(this)
onto the end of a function declaration, I got a syntax error whether using a traditional function declaration, an arrow function, etc.
If I tried saving the function as a variable name, then adding .bind(this)
to that variable, I got the same syntax error.
I ended up figuring out to tack the bound method onto my event listener declaration name and store that as a new variable name on the object that is the this
context for that function. This is the only way it would work.
Then, in the .addEventListener call, I pass in the bound function I've stored on the this
object.
My final code that works correctly is:
function escapeKeydownEventHandler(event){
const index = this.value;
// ...
};
function clicksOutsideDeleteConfirmationContainerEventHandler(event){
const clickTarget = event.explicitOriginalTarget;
const index = this.value;
// ...
};
function deleteConfirmationCancelButtonClickEventHandler(event){
const index = this.value;
// ...
document.removeEventListener('keydown', this.escapeKeydownEventHandlerBound, false);
document.body.removeEventListener('click', this.clicksOutsideDeleteConfirmationContainerEventHandlerBound, false);
deleteConfirmationCancelButton[index].removeEventListener('click', this.deleteConfirmationCancelButtonClickEventHandlerBound, false);
// ...
};
function clickEventHandler(event){
const index = this.value;
// ...
this.escapeKeydownEventHandlerBound = escapeKeydownEventHandler.bind(this);
this.clicksOutsideDeleteConfirmationContainerEventHandlerBound = clicksOutsideDeleteConfirmationContainerEventHandler.bind(this);
this.deleteConfirmationCancelButtonClickEventHandlerBound = deleteConfirmationCancelButtonClickEventHandler.bind(this);
document.addEventListener('keydown', this.escapeKeydownEventHandlerBound, false);
document.body.addEventListener('click', this.clicksOutsideDeleteConfirmationContainerEventHandlerBound, false);
deleteConfirmationCancelButton[index].addEventListener('click', this.deleteConfirmationCancelButtonClickEventHandlerBound, false);
// ...
};
I shortened up the variable names for the sake of readability.