views:

166

answers:

4

Hi,

I would like to remove ALL handlers for a given event type. Let's say I've added twice "onclick event" to a button and now I would like to return back to the original state where no event handler was set to the button.

How can I do that?

P.S.: I've found removeEventListener (non-IE)/detachEvent (IE) methods but the functions want me to pass as a parameter the function that handles the event which seems to me quite clumsy because I would have to store the functions somewhere.

EDIT: http://ejohn.org/blog/flexible-javascript-events/ - I'm now using this code

Thank you!

A: 

According to this thread, you can use cloneNode to strip all the event listeners from a javascript element, like so:

 var new_element = old_element.cloneNode(true);
 old_element.parentNode.replaceChild(new_element, old_element);
MatW
Yeah, but the following sentence is: I believe that attachEvent persists even when an element is cloned though, so I’m not sure what you would do for Internet Explorer users.
MartyIX
+1  A: 

It might be a good idea to use jQuery or a similar framework to manage all event handlers. This will give you easy-to-use, unobtrusive functions to add and remove event handlers:

$(...).bind('click', function() { ... });
$(...).unbind('click');
// or, to unbind all events:
$(...).unbind();
ThiefMaster
I would like to understand how it works. Does it simply store the functions somewhere and unbind() simply go through the list of functions and call removeEventListener?
MartyIX
It stores an event list internally
ThiefMaster
A: 

As far as I know, you cannot add two onclick handlers to an element at all.

Say obj is an element then the property onclick of obj is considered a function and then called as a method whenever that event occurs. If it's not a function nothing will happen.

JavaScript inherited from Scheme a very interesting property, in JavaScript, you don't define functions as in PHP or C. You create anonymous functions and store them in a variable. Javascript is 'Lisp-1', there are no function identifiers, there are variables, which can house numbers, arrays, and functions.

function name(arg) {return arg;}

Is if I'm not mistaken truly sugar for:

name = function(arg) {return arg;};

'name' here is a variable, we can also re-asign it no matter how we defined that function. Unlike Java's object model, in Javascript, a 'method' is purely a property, a variable that simply holds a function that may or may not use the 'this' keyword. This is why you can't have two onclick event at the same time. The runtime environment simply calls the property (which is expected to house a function) of the element called 'onclick' whenever you click on it. See it as the same ad hoc type behaviour of calling 'main' to start a program.

To assign multiple event handlers, you use a function with a side effect, like.

obj.onclick = function {firstEvent();secondEvent();}

To change or remove it, we re-assign or de-assign it like any variable.

obj.onclick = null;

And in case we need to invoke that behaviour in another way:

obj.onclick();

We can also use this in that function of course to change the object itself or reference it.

Edit: Oh wait, I see now that you mean wih 'a button' many different buttons.

Well, then you just collect all elements like:

allElements = document.getElementsByTagName('*');

And then you use a loop:

var i = 0; while(obj = allElements[i++]) obj.onclick = null;

(and no, that single = is not a typo)

Lajla
http://pastebin.org/237133 - this is an example of a code that calls two onclick handlers for one button. (Tested in Firefox and Chrome)
MartyIX
I ment really only a one button not many.
MartyIX
+1  A: 

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>
MartyIX