How Would It Be Possible to Remove All Event Handlers of the 'Click' Event of a 'Button'

Is it possible to remove all event handlers of a given element in javascript?

http://www.quirksmode.org/js/events_advanced.html - "Which event handlers are registered?" - it seems it's not possible without DOM 3 level :-(

EDIT: I've come up with this code. It suits my needs. Maybe it will be helpful for someone else.

Javascript:

function DomLib() {

}

/**
* Based on: http://ejohn.org/blog/flexible-javascript-events/
* Function that register event and enables it to be removed without explicitly giving the function definition
*/
DomLib.prototype.regEventEx = function (el, eventName, funct) {

if (el.attachEvent) {
el['e'+eventName+funct] = funct;
el[eventName+funct] = function(){el['e'+eventName+funct](window.event);}
el.attachEvent( 'on'+eventName, el[eventName+funct] );
} else {
el.addEventListener(eventName, funct, false);
}

if(!el.eventHolder) el.eventHolder = [];
el.eventHolder[el.eventHolder.length] = new Array(eventName, funct);
}

DomLib.prototype.removeEvent = function (obj, type, fn) {
if (obj.detachEvent) {
obj.detachEvent( 'on'+type, obj[type+fn] );
obj[type+fn] = null;
} else {
obj.removeEventListener( type, fn, false );
}
}

DomLib.prototype.hasEventEx = function (el, eventName, funct) {

if (!el.eventHolder) {
return false;
} else {
for (var i = 0; i < el.eventHolder.length; i++) {
if (el.eventHolder[i][0] == eventType && String(el.eventHolder[i][1]) == String(funct)) {
return true;
}
}
}
return false;
}

/**
* @return - returns true if an event was removed
*/
DomLib.prototype.removeEventsByTypeEx = function (el, eventType) {

if (el.eventHolder) {

var removed = 0;
for (var i = 0; i < el.eventHolder.length; i++) {
if (el.eventHolder[i][0] == eventType) {
this.removeEvent(el, eventType, el.eventHolder[i][1]);
el.eventHolder.splice(i, 1);
removed++;
i--;
}
}

return (removed > 0) ? true : false;
} else {
return false;
}
}

Testing HTML page:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<meta http-equiv="Expires" content="Fri, Jan 01 1900 00:00:00 GMT">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Cache-Control" content="no-cache">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta http-equiv="Lang" content="en">
<meta name="author" content="">
<meta http-equiv="Reply-to" content="@.com">
<meta name="generator" content="PhpED 5.8">
<meta name="description" content="">
<meta name="keywords" content="">
<meta name="creation-date" content="01/01/2009">
<meta name="revisit-after" content="15 days">
<title>DomLibTest</title>
<link rel="stylesheet" type="text/css" href="my.css">
<!-- FILL IN: Location of your jQuery library -->
<script type="text/javascript" src="jQuery/jQuery-current.js"></script>
<!-- FILL IN: Plugin for debugging ... http://www.ecitadel.net/blog/2009/12/08/developing-jquery-use-dump-instead-alert -->
<script type="text/javascript" src="jQuery/jQuery.dump.js"></script>
<script type="text/javascript" src="DomLib.js"></script>
</head>
<body>

<div id="testElem-1"></div>
<script type="text/javascript">
<!--

var domLib = new DomLib();

function removeTest(el) {

var funct = function() { alert("#1: How Are You?");};
var funct2 = function() { alert("#2: How Are You?");};

domLib.regEventEx(el, "click", funct);
domLib.regEventEx(el, "mousemove", funct2);
domLib.regEventEx(el, "mousemove", funct2);
domLib.regEventEx(el, "mousemove", funct2);

$.dump(el.eventHolder);
domLib.removeEventsByTypeEx(el, "mousemove");
$.dump(el.eventHolder);
}

removeTest(document.getElementById('testElem-1'));

-->
</script>
</body>
</html>

How to remove all event handlers from an event

I found a solution on the MSDN forums. The sample code below will remove all Click events from button1.

public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();

button1.Click += button1_Click;
button1.Click += button1_Click2;
button2.Click += button2_Click;
}

private void button1_Click(object sender, EventArgs e) => MessageBox.Show("Hello");
private void button1_Click2(object sender, EventArgs e) => MessageBox.Show("World");
private void button2_Click(object sender, EventArgs e) => RemoveClickEvent(button1);

private void RemoveClickEvent(Button b)
{
FieldInfo f1 = typeof(Control).GetField("EventClick",
BindingFlags.Static | BindingFlags.NonPublic);

object obj = f1.GetValue(b);
PropertyInfo pi = b.GetType().GetProperty("Events",
BindingFlags.NonPublic | BindingFlags.Instance);

EventHandlerList list = (EventHandlerList)pi.GetValue(b, null);
list.RemoveHandler(obj, list[obj]);
}
}

How would it be possible to remove all event handlers of the 'Click' event of a 'Button'?

You can't, basically - at least not without reflection and a lot of grubbiness.

Events are strictly "subscribe, unsubscribe" - you can't unsubscribe someone else's handler, any more than you can change someone else's reference to an object.

How to remove all Click event handlers?

The below is a helpful utility method for retrieving all subscribed event handlers for any routed event:

/// <summary>
/// Gets the list of routed event handlers subscribed to the specified routed event.
/// </summary>
/// <param name="element">The UI element on which the event is defined.</param>
/// <param name="routedEvent">The routed event for which to retrieve the event handlers.</param>
/// <returns>The list of subscribed routed event handlers.</returns>
public static RoutedEventHandlerInfo[] GetRoutedEventHandlers(UIElement element, RoutedEvent routedEvent)
{
// Get the EventHandlersStore instance which holds event handlers for the specified element.
// The EventHandlersStore class is declared as internal.
var eventHandlersStoreProperty = typeof(UIElement).GetProperty(
"EventHandlersStore", BindingFlags.Instance | BindingFlags.NonPublic);
object eventHandlersStore = eventHandlersStoreProperty.GetValue(element, null);

// Invoke the GetRoutedEventHandlers method on the EventHandlersStore instance
// for getting an array of the subscribed event handlers.
var getRoutedEventHandlers = eventHandlersStore.GetType().GetMethod(
"GetRoutedEventHandlers", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
var routedEventHandlers = (RoutedEventHandlerInfo[])getRoutedEventHandlers.Invoke(
eventHandlersStore, new object[] { routedEvent });

return routedEventHandlers;
}

Using the above, the implementation of your method becomes quite simple:

private void RemoveClickEvent(Button b)
{
var routedEventHandlers = GetRoutedEventHandlers(b, ButtonBase.ClickEvent);
foreach (var routedEventHandler in routedEventHandlers)
b.Click -= (RoutedEventHandler)routedEventHandler.Handler;
}

remove all EventHandlers of a specific Control

According to this,
for cancelling all Click Events of panel1 do this:

FieldInfo f1 = typeof(Control).GetField("EventClick", BindingFlags.Static| BindingFlags.NonPublic);
object obj = f1.GetValue(panel1);
PropertyInfo pi = panel1.GetType().GetProperty("Events", BindingFlags.NonPublic | BindingFlags.Instance);
EventHandlerList list = (EventHandlerList)pi.GetValue(panel1, null);
list.RemoveHandler(obj, list[obj]);

And for cancelling other events of panel1 change EventClick to event name that you want to remove.

One can get all event names using this code:

EventInfo[] info = type.GetEvents();
for (int i = 0; i < info.Length; i++)
{
Console.WriteLine(info[i].Name + "\n");
}

Javascript/DOM: How to remove all event listeners of a DOM object?

I am not sure what you mean with remove all events. Remove all handlers for a specific type of event or all event handlers for one type?

Remove all event handlers

If you want to remove all event handlers (of any type), you could clone the element and replace it with its clone:

var clone = element.cloneNode(true);

Note: This will preserve attributes and children, but it will not preserve any changes to DOM properties.



Remove "anonymous" event handlers of specific type

The other way is to use removeEventListener() but I guess you already tried this and it didn't work. Here is the catch:

Calling addEventListener to an anonymous function creates a new listener each time. Calling removeEventListener to an anonymous function has no effect. An anonymous function creates a unique object each time it is called, it is not a reference to an existing object though it may call one. When adding an event listener in this manner be sure it is added only once, it is permanent (cannot be removed) until the object it was added to, is destroyed.

You are essentially passing an anonymous function to addEventListener as eventReturner returns a function.

You have two possibilities to solve this:

  1. Don't use a function that returns a function. Use the function directly:

     function handler() {
    dosomething();
    }

    div.addEventListener('click',handler,false);
  2. Create a wrapper for addEventListener that stores a reference to the returned function and create some weird removeAllEvents function:

     var _eventHandlers = {}; // somewhere global

    const addListener = (node, event, handler, capture = false) => {
    if (!(event in _eventHandlers)) {
    _eventHandlers[event] = []
    }
    // here we track the events and their nodes (note that we cannot
    // use node as Object keys, as they'd get coerced into a string
    _eventHandlers[event].push({ node: node, handler: handler, capture: capture })
    node.addEventListener(event, handler, capture)
    }

    const removeAllListeners = (targetNode, event) => {
    // remove listeners from the matching nodes
    _eventHandlers[event]
    .filter(({ node }) => node === targetNode)
    .forEach(({ node, handler, capture }) => node.removeEventListener(event, handler, capture))

    // update _eventHandlers global
    _eventHandlers[event] = _eventHandlers[event].filter(
    ({ node }) => node !== targetNode,
    )
    }

And then you could use it with:

    addListener(div, 'click', eventReturner(), false)
// and later
removeAllListeners(div, 'click')

DEMO

Note: If your code runs for a long time and you are creating and removing a lot of elements, you would have to make sure to remove the elements contained in _eventHandlers when you destroy them.

Best way to remove an event handler in jQuery?

jQuery ≥ 1.7

With jQuery 1.7 onward the event API has been updated, .bind()/.unbind() are still available for backwards compatibility, but the preferred method is using the on()/off() functions. The below would now be,

$('#myimage').click(function() { return false; }); // Adds another click event
$('#myimage').off('click');
$('#myimage').on('click.mynamespace', function() { /* Do stuff */ });
$('#myimage').off('click.mynamespace');

jQuery < 1.7

In your example code you are simply adding another click event to the image, not overriding the previous one:

$('#myimage').click(function() { return false; }); // Adds another click event

Both click events will then get fired.

As people have said you can use unbind to remove all click events:

$('#myimage').unbind('click');

If you want to add a single event and then remove it (without removing any others that might have been added) then you can use event namespacing:

$('#myimage').bind('click.mynamespace', function() { /* Do stuff */ });

and to remove just your event:

$('#myimage').unbind('click.mynamespace');

How to remove all click event handlers using jQuery?

You would use off() to remove an event like so:

$("#saveBtn").off("click");

but this will remove all click events bound to this element. If the function with SaveQuestion is the only event bound then the above will do it. If not do the following:

$("#saveBtn").off("click").click(function() { saveQuestion(id); });

Remove All Event Listeners of Specific Type

That is not possible without intercepting addEventListener calls and keep track of the listeners or use a library that allows such features unfortunately. It would have been if the listeners collection was accessible but the feature wasn't implemented.

The closest thing you can do is to remove all listeners by cloning the element, which will not clone the listeners collection.

Note: This will also remove listeners on element's children.

var el = document.getElementById('el-id'),
elClone = el.cloneNode(true);

el.parentNode.replaceChild(elClone, el);


Related Topics



Leave a reply



Submit