312

I have a button, and I added some eventlistners to it:

document.getElementById("btn").addEventListener("click", funcA, false);
document.getElementById("btn").addEventListener("click", funcB, false);
document.getElementById("btn").addEventListener("click", funcC, false);
document.getElementById("btn").addEventListener("blur" , funcD, false);
document.getElementById("btn").addEventListener("focus", funcE, false);

<button id="btn">button</button>

I can remove them by:

document.getElementById("btn").removeEventListener("click",funcA);

What if I want I want to remove all listeners at once, or I don't have the function reference (funcA)? Is there a way of doing that, or I have to remove them one by one?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Derek 朕會功夫
  • 92,235
  • 44
  • 185
  • 247
  • http://stackoverflow.com/questions/3222486/remove-all-javascript-event-listeners-of-an-element-and-its-children – Misiur Feb 12 '12 at 19:21
  • 108
    Up-voted for attempting to competently code by NOT using frameworks/libraries. :-) – John Feb 12 '12 at 20:51
  • 2
    @user Impressive, you actually found a question that is even older than this old question where the answers here are still mentioning jQuery 1.7. Can't believe how much time has passed since I asked this question. – Derek 朕會功夫 Jan 09 '16 at 13:27

3 Answers3

313

I think that the fastest way to do this is to just clone the node, which will remove all event listeners:

var old_element = document.getElementById("btn");
var new_element = old_element.cloneNode(true);
old_element.parentNode.replaceChild(new_element, old_element);

Just be careful, as this will also clear event listeners on all child elements of the node in question, so if you want to preserve that you'll have to resort to explicitly removing listeners one at a time.

Ben D
  • 14,321
  • 3
  • 45
  • 59
  • Thanks! And I used your code like this `function unbind(ele){ele.parentNode.replaceChild(ele.cloneNode(true), ele);}` – Derek 朕會功夫 Feb 12 '12 at 19:42
  • 74
    @Derek: Cloning a node and the whole subtree is a bad idea. It is **much** slower than removing all the `EventListener`s from the node with `node.removeEventListener`. In addition you will get a memory leak (node + subtree) and off course all `EventListener`s were removed from the subtree. If you use your function on `document.body` you will blow up everything. – Saxoier Feb 13 '12 at 00:04
  • 1
    @Saxoier, Thanks for the reminder but I tested on this page's `body` and it worked like a charm. Maybe I'm using a fast browser (Google Chrome). – Derek 朕會功夫 Feb 13 '12 at 02:27
  • 7
    @Saxoier certainly cloning the node is slower than just removing the listeners, but in most functional scenarios the speed difference will not be discernible (unless you're doing this to a huge number of the page nodes all in one go). As for the memory leak, this will be browser dependent... All the modern browsers should handle garbage collection well enough to not experience a problem (though if the node contains embedded objects I could imagine scenarios where this could happen). Do you have a specific documented memory leak in mind? – Ben D Feb 13 '12 at 04:27
  • 1
    @Saxoier your note about the effect of cloning on event listeners in the sub-tree of the node is worth explicit mention... I've added the warning to my answer, as people should be aware of this. – Ben D Feb 13 '12 at 04:35
  • 1
    @Ben D: It seems that the latest versions of Firefox, IE, Opera and Chrome [have a decent GC](http://fiddle.jshell.net/VwMrK/) (summary after 10 GC cycles). Under certain circumstances [older IE will leak](http://javascript.crockford.com/memory/leak.html). – Saxoier Feb 13 '12 at 09:08
  • Is it possible to clone a node without loosing its listeners? – Shawn May 02 '12 at 03:27
  • @Saxoier, from your comment I understood that cloning is slow and inefficient operation. But what about just creating a new element (`document.createElement('canvas')` for example)? – Ivan Kochurkin Jan 12 '13 at 13:29
  • 26
    For those who hate mysterious boolean arguments, cloneNode(true) means to clone the node including children. Documentation: https://developer.mozilla.org/en-US/docs/Web/API/Node.cloneNode – Andrew Dunkman Jul 24 '13 at 19:11
  • A downvote... interesting. – Ben D Jul 26 '13 at 19:35
  • 5
    @BenD interesting there are 3 down votes but no alternative answers... that's a pretty weak show by those down voters! – AJP Apr 14 '14 at 10:20
  • perhaps clone the node _without_ children, then move the children over. – Eevee Aug 12 '14 at 23:12
  • What if the element is the root `html` which does not have a parent element. – Meow Dec 16 '17 at 17:10
  • @Meow - `html` actually does have a parent: the `document` itself. I'm not sure I can think of a case where you'd have listeners attached to the `html` element instead of the `body` or a wrapper, but In theory, this should work with an `` node (``'s parentNode is just the `document`, so the logic would work). However, I ran a couple of tests and some browsers seem have trouble replacing the `document.html` node, so in practical use I'd avoid it (though I'd also avoid adding listeners to `html` as well) – Ben D Dec 31 '17 at 03:59
  • Apparently it does not remove callbacks added with html – DarthCadeus Dec 15 '18 at 03:21
  • might be a bad idea, but seems like the only viable option – stackers Oct 22 '20 at 23:00
  • This sure is too much of a nuclear option if the event listener was registered on the window object. – Pangamma Jun 02 '21 at 03:54
  • This is not removing attributes like `onpsate`. – haridsv Aug 31 '21 at 06:57
  • A perhaps more elegant solution is to simply extend EventTarget, overriding its addEventListener and removeEventListener methods to maintain a data structure containing your handler function references. I take this approach in another thread: https://stackoverflow.com/a/74285228/15347182 . There are tests in the full Gist (https://gist.github.com/angstyloop/504414aba95b61b98be0db580cb2a3b0) linked in angsyloop's comment, which you can run in your browser console. Please read strange JS before running it in your browser console. – angstyloop Nov 02 '22 at 06:47
58

If you’re using jquery events, this can be done in one line:

For jQuery events (.on()):

$("#myEl").off()

For native javascript events (.addEventListener()):

$('#myEl').replaceWith($('#myEl').clone());

Here’s an example:

http://jsfiddle.net/LkfLezgd/3/

Duke
  • 7,070
  • 3
  • 38
  • 28
  • 2
    That's too long, instead in jQuery you should do this `$("#myEl").unbind();` or `.off()` (1.7+) to remove all listeners. – Derek 朕會功夫 Feb 06 '15 at 22:40
  • 31
    Do `off()` or `unbind()` only remove those listeners attached via jQuery? – davide Feb 26 '15 at 03:45
  • Just re-read the docs on .off(), and it does allow you to omit all the parameters to remove all event binding. With .unbind(), however, eventType is mandatory and thus unusable for this purpose. – Duke Apr 06 '15 at 18:31
  • 5
    don't know why that `unbind` and `off` doesn't work. However the `$('#myEl').replaceWith($('#myEl').clone());` works great! – AGamePlayer Jan 13 '16 at 15:25
  • 34
    @davide @Duke indeed `off()` and `unbind()` would not work for listeners registered with native javascript `addEventListener`, as per jquery docs. – argaz Oct 26 '16 at 07:40
  • 5
    It looks like this will only remove events created with jQuery, therefore not a complete solution. – Nathan B Jun 05 '18 at 08:33
  • The clone should remove all event listeners period. Similar to the accepted answer, just more readable. – Duke Sep 20 '18 at 22:26
  • I appreciate that this answer started with "If you're not opposed to jquery" - way too many answers are "just use jquery" (when sometimes, company policy forbids it). – FinrodFelagund May 07 '20 at 14:11
  • $('#myEl').replaceWith($('#myEl').clone()); Its worked for me, thanks – Javed Iqbal Mar 02 '21 at 07:48
  • I like how the non-jquery answer still uses jquery lol – Rick Kukiela May 05 '23 at 17:03
27

Here's a function that is also based on cloneNode, but with an option to clone only the parent node and move all the children (to preserve their event listeners):

function recreateNode(el, withChildren) {
  if (withChildren) {
    el.parentNode.replaceChild(el.cloneNode(true), el);
  }
  else {
    var newEl = el.cloneNode(false);
    while (el.hasChildNodes()) newEl.appendChild(el.firstChild);
    el.parentNode.replaceChild(newEl, el);
  }
}

Remove event listeners on one element:

recreateNode(document.getElementById("btn"));

Remove event listeners on an element and all of its children:

recreateNode(document.getElementById("list"), true);

If you need to keep the object itself and therefore can't use cloneNode, then you have to wrap the addEventListener function and track the listener list by yourself, like in this answer.

Donald Duck
  • 8,409
  • 22
  • 75
  • 99
user
  • 23,260
  • 9
  • 113
  • 101