...

View Full Version : RemoveEvent Does Not Work



BarrMan
04-27-2008, 03:16 PM
Hey,
I'm trying to use the removeEvent function to clear an "onclick" event from my anchor.

It does not work for some reason and I have no idea why.
Can anyone help me please with this code:

Thanks:


img = document.getElementById("image"+i);
anchor = document.getElementById("anchor"+i);
img.src = directory + image[first+i-times];
img.alt = image[first+i-times];
anchor.HRef="#";
/*anchor.setAttribute("onclick",null); Ignore this*/
removeEvent(anchor,"click",evtHandle);
evtHandle = (function(id)
{
return function()
{
changePic(id);
changeInfo(id);
return false;
};
})(first+i-times);
addEvent(anchor,"click",evtHandle);

evtHandle is a global variable.

Trinithis
04-28-2008, 06:53 AM
I can't help you much until you post your code for addEvent and removeEvent.

However, if you substitute these definitions into your code, does your it work?


var addEvent = window.addEventListener
? function(el, t, f) {
el.addEventListener(t, f, false);
}
: function(el, t, f) {
el.attachEvent("on" + t, f);
};

var removeEvent = window.removeEventListener
? function(el, t, f) {
el.removeEventListener(t, f, false);
}
: function(el, t, f) {
el.detachEvent("on" + t, f);
};

BarrMan
04-29-2008, 12:11 PM
Oh, Sorry, I forgot about that :D


function addEvent(obj, type,fn)
{
if(obj.attachEvent)
{
obj["e"+type+fn] = fn;
obj[type+fn] = function() { obj["e"+type+fn]( window.event ); }
obj.attachEvent( "on"+type, obj[type+fn] );
}
else if(obj.addEventListener)
obj.addEventListener(type,fn,false);
else
obj["on"+type] = fn;
}

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

Here it is.

Edit: The removeEvent function throws an error on IE.

SSJ
04-29-2008, 12:26 PM
Oh, Sorry, I forgot about that :D


function addEvent(obj, type,fn)
{
if(obj.attachEvent)
{
obj["e"+type+fn] = fn;
obj[type+fn] = function() { obj["e"+type+fn]( window.event ); }
obj.attachEvent( "on"+type, obj[type+fn] );
}
else if(obj.addEventListener)
obj.addEventListener(type,fn,false);
else
obj["on"+type] = fn;
}

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

Here it is.
Yes I think this is the perfect code :)

BarrMan
04-30-2008, 02:02 PM
Bump.

Trinithis
04-30-2008, 06:24 PM
Works for me.

I would not turn the function into a string to store it in the object's events propery. That is too wasteful. I would recommend an array that stores the function and then you can compare against identity.

Also, you could enhance the window.event object before you toss it into the handler so it behaves like a firefox event. Eg: window.event.target = window.event.srcElement.

Code I used to test it.


<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Test</title>
</head>
<body><div>

<div id="message">Click Me</div>

<script type="text/javascript">

function addEvent(obj, type,fn)
{
if(obj.attachEvent)
{
obj["e"+type+fn] = fn;
obj[type+fn] = function() { obj["e"+type+fn]( window.event ); }
obj.attachEvent( "on"+type, obj[type+fn] );
}
else if(obj.addEventListener)
obj.addEventListener(type,fn,false);
else
obj["on"+type] = fn;
}

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

function testClick(e) {
var el = e.target
? e.target
: e.srcElement;
alert("turning off the handler for '" + el.id + "'");
try {
removeEvent(el, "click", arguments.callee);
alert("no error");
}
catch(ex) {
alert("error!")
}
}

var div = document.getElementById("message");

addEvent(div, "click", testClick);

</script>
</div></body>
</html>

BarrMan
05-01-2008, 12:24 PM
Hey. Thanks!

It works for me when I try your page but it doesn't seem to work on my page. It somehow has something to do with the variable evtHandle which contains the 2 functions. How can I remove this event?

Also, I'm not too sure what arguments.callee mean.

Trinithis
05-01-2008, 04:23 PM
arguments.callee means the function that is currently in execution. In this case, you could replace it with testClick if you really wanted to, but arguments.callee is slightly better. If you modify your code and change the name of the function, you have one less place to change. The real benefit though happens when you do something like this:



function fact(n) {
return n * fact(n - 1);
}

var f = fact;

fact = function() {
alert("Fun fact: the function f won't recurse properly!");
}




function fact(n) {
return n * arguments.callee(n - 1);
}

var f = fact;

fact = function() {
alert("Fun fact: the function f will recurse properly!");
}

BarrMan
05-01-2008, 06:09 PM
Oh, Thanks I see that now.
But still, my first problem isn't solved.

How can I make the same thing I did on my code and be able to remove the events later on?

BarrMan
05-03-2008, 01:40 AM
Bump.

Trinithis
05-03-2008, 03:09 AM
You need to post more code. I can't deduce anything from what's already here.

BarrMan
05-03-2008, 11:54 AM
Here, try this:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Test</title>
</head>
<body><div>

<div id="message">Click Me</div>

<script type="text/javascript">

function addEvent(obj, type,fn)
{
if(obj.attachEvent)
{
obj["e"+type+fn] = fn;
obj[type+fn] = function() { obj["e"+type+fn]( window.event ); }
obj.attachEvent( "on"+type, obj[type+fn] );
}
else if(obj.addEventListener)
obj.addEventListener(type,fn,false);
else
obj["on"+type] = fn;
}

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

function testClick(e) {
var el = e.target
? e.target
: e.srcElement;
alert("turning off the handler for '" + el.id + "'");
try {
removeEvent(el, "click",evtHandle);// arguments.callee);
alert("no error");
}
catch(ex) {
alert("error!")
}
}

var div = document.getElementById("message");
var evtHandle = function(){return function(){testClick();return false;};};
addEvent(div, "click", evtHandle);

</script>
</div></body>
</html>

Trinithis
05-03-2008, 08:39 PM
The solution:


var evtHandle = function(e) {
testClick(e);
return false;
};


I revamped the addEvent code, but it is not needed for your code to work. But it is better.


function addEvent(el, type, f) {
if(el.addEventListener)
el.addEventListener(type, f, false);
else if(el.attachEvent) {
if(!el.evtHandlers)
el.evtHandlers = [];
var hldObj;
for(var i = el.evtHandlers.length - 1; i >= 0; --i) {
hldObj = el.evtHandlers[i];
if(hldObj.type === type && hldObj.callback === f)
return; // if the handler already exists, don't add it
}
hldObj = {
type: type,
callback: f,
handler: function() {
var e = window.event;
e.target = e.srcElement;
// add more standard attributes to e here
f(e);
}
};
el.evtHandlers.push(hldObj);
el.attachEvent("on"+type, hldObj.handler);
}
else
el["on"+type] = f;
el = null;
}

function removeEvent(el, type, f) {
if(el.removeEventListener)
el.removeEventListener(type, f, false);
else if(el.detachEvent) {
if(!el.evtHandlers)
return; // return if no handler attached
var hldObj;
for(var i = el.evtHandlers.length - 1; i >= 0; --i) {
hldObj = el.evtHandlers[i];
if(hldObj.type === type && hldObj.callback === f)
break;
}
if(i === -1)
return; // return if the handler does not exist
el.evtHandlers.splice(i, 1);
el.detachEvent("on"+hldObj.type, hldObj.handler);
}
else
el["on"+type] = null;
}

BarrMan
05-03-2008, 09:50 PM
Hey, Thanks for the reply.

The problem still remains. You've change my function's structure and that's why it works. The function structure is necessary because it doesn't work otherwise.

Can you try to make it work with the current structure?

function(){return function(){testClick(e); return false;};}

Thanks!

Trinithis
05-03-2008, 10:51 PM
What you have:


function evtHandle() {
return function() { // really should have the e parameter
testClick(e);
return false;
};
}


Event handlers always have the form:


function(e) {
do something
};

You can leave out the e parameter in the function if you never use it inside. In that case, arguments[0] is equal to the event object.

So in your case, whenever the event is triggered, your event handler does the following:

It simply returns a function and does nothing else.

In essense it does absolutely nothing!

What your evtHandle function does do is generate an event handling function (assuming you fix it by adding the e parameter to the returned function):


addEvent(el, "click", evtHandle()); // note evtHandle is being called!

However, this adds an anonymous function to el. And it should be noted that anyonymous functions cannot be removed if added using DOM methods (addEventListener / attachEvent).

The only way to remove it is to keep a reference to the anonymous function:


// functions compare by identity
alert(evtHandle() === evtHandle()); // false
var hdl = evtHandle();
alert(hdl === hdl); // true

// The following won't work because evtHandle() generates a new function
addEvent(el, "click", evtHandle()); // adds the event, but it cannot be removed
removeEvent(el, "click", evtHandle()); // oops! not same function

// This works
addEvent(el, "click", hdl);
removeEvent(el, "click", hdl);


Sorry, you're stuck. There's nothing you can do about it except change your game plan.

BarrMan
05-05-2008, 09:02 AM
Hey, Thanks for your reply!

I have to keep the existing structure because I have to get the values to the function parameter from outside the function.

How can I achieve this?

Thanks again!

Trinithis
05-05-2008, 05:02 PM
You could try binding an object's method to the event handler and have the object keep track of the info. Then you can simply forget about the attached method and only keep track of the object holding the info. You could also do a similar thing without a method, but using a closure to close over the object.

Or you could do something like this:


var innerHandler = function(e) {
....
}

var handler = function(e) {
innerHandler(e);
};


Then you can keep handler the same, but when you need to change its functionality, you can change what innerHandler is pointing to.

Or you could give up the DOM way of adding events and just use onclick. Then getting rid of the handler is trivial: Just reassign it.

BarrMan
05-05-2008, 06:09 PM
Thanks! I'll try that and keep you updated.



EZ Archive Ads Plugin for vBulletin Copyright 2006 Computer Help Forum