Remove keydown/keyup document.eventListener when element is deleted

511 Views Asked by At

I have a div with id "div1" that gets updated when the user presses keys. I have added an eventlistener for the keydown event that runs a function "update" and attached it to the document as follows:

let div=document.getElementById("div1");
document.addEventListener("keydown",update);
div.remove()
//event listener remains listening, because it's attached to document

When "div1" is removed from the DOM, the event listener remains. If I added the event listener to "div1", then the event listener would be removed when div1 is removed from the DOM.

let div=document.getElementById("div1");
div.addEventListener("keydown",update);
div.remove()
//event listener removed, no more listening

This approach doesn't work however, since the element has to be focused for the keydown event to trigger and my div1 doesn't have focus and I want the user to be able to update without clicking on the item anyway.

Is there a way to automatically remove the event listener when the element is deleted (as in case 2) even though the event listener is attached to the document (as in case 1). Alternatively, is there another alternative for attaching the event listener to the element and still listening for all keydown events.

3

There are 3 best solutions below

0
Gihan On

You can use event delegation. Then you can check the event target in the callback to see if it matches the removed element so you can unbind the event listener.

 let parent = document.getElementById("parent");
    parent.addEventListener("keydown", function(event) {
      let target = event.target;
      if (target.id === "div1") {
        update();
        parent.removeEventListener("keydown", arguments.callee);
      }
    });
0
T.J. Crowder On

You can remove that event listener with a MutationObserver observing changes to div1's parent element and looking to see if div1 was removed by the change:

let div1 = document.getElementById("div1");

// Add the handler
let handler = (event) => {
    console.log(`key pressed: ${event.key}`);
};
document.addEventListener("keydown", handler);

// Watch for changes to the parent of the div
const observer = new MutationObserver((mutationList) => {
    // If `div1` is done, remove the event handler and
    // stop listening for changes.
    // You could use `mutationList` here if you liked rather than
    // doing getElementById
    if (!document.getElementById("div1")) {
        console.log("div1 is gone, removing handler and mutation observer");
        div = null; // Not necessary, but probably good
        document.removeEventListener("keydown", handler);
        observer.disconnect();
        handler = null; // Not necessary, but probably good
    }
});
observer.observe(div1.parentElement, { childList: true, subtree: true });

// Just a way to remove the div
document.querySelector("input[value='Remove div1']").addEventListener("click", () => {
    div1.remove();
    div1 = null;
});
<div id="div1">This is div1</div>
<input type="button" value="Remove div1">

1
user1763510 On

Here is a slightly more passive way than using the MutationObserver (element will only be removed the first time the event is fired after removal, rather than when the element is removed):

document.addEventListener("keydown",update);

function update(){
  let div=document.getElementById("div1");
  if(div===null || div.isConnected===false){//div1 is currently not attached to DOM
    document.removeEventListener("keydown",update);
    return;  
  }
  //other update code here
}