Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ActionScript 3.0 using closures for event handlers

I tried doing this:

root.addEventListener("click", 
   function () 
   { 
      navigateToURL(ClickURLRequest,"_self"); 
   });

And it does add the event listener. I like using closures because they work well in this situation,

however, removing the event listener requires a reference to the original function, and since I used an anonymous closure, it does not work, I tried:

   root.removeEventListener("click", 
       function () 
       { 
          navigateToURL(ClickURLRequest,"_self"); 
       });

as well as:

   root.removeEventListener("click", function () {} );

The only way I found it would work was to ditch the anonymous closure and point the event listeners at a pre-existing function:

 function OnClick (e:Event)
 {
     navigateToURL(ClickURLRequest,"_self");
 }

 root.addEventListener("click", OnClick);
 root.removeEventListener("click", OnClick);

Does anyone know a way to use anonymous closures for event handlers while still retaining the ability to remove them?

like image 745
FlySwat Avatar asked Oct 07 '08 18:10

FlySwat


3 Answers

Here's a generic way of removing event listeners that i have used on production projects


addEventListener
(
    Event.ACTIVATE, 
    function(event:Event):void
    {
        (event.target as EventDispatcher).removeEventListener(event.type, arguments.callee)             
    }
)
like image 133
BefittingTheorem Avatar answered Nov 03 '22 01:11

BefittingTheorem


As has already been suggested, you may remove the closure from the chain of listeners from within the closure itself. This is done through the use of arguments.callee:

myDispatcher.addEventListener("click", function(event:Event):void
{
    IEventDispatcher(event.target).removeEventListener(event.type, arguments.callee);

    // Whatever else needs doing goes here
});

This will effectively turn the closure into a one-time listener of the event, simply detaching itself once the event has fired. While syntactically verbose, it's an incredibly useful technique for those many events that really only fire once (or that you only care about once) like "creationComplete" in Flex, for instance. I use this all the time when downloading data, since I think having the callback code inline makes it easier to understand. It is like hiding away the asynchronous-ness:

myLoader.addEventListener("complete", function(event:Event):void
{
    /* Even though the load is asynchronous, having the callback code inline
     * like this instead of scattered around makes it easier to understand,
     * in my opinion. */
});

However, if you want to listen to the event multiple times, this will not be very effective for obvious reasons. In that case, you need to store a reference to the closure somewhere. Methods are objects like anything else in ActionScript and can be passed around. Thus, we can alter our code to look like this:

var closure:Function;

myDispatcher.addEventListener("click", function(event:Event):void
{
    closure = arguments.callee;

    // Whatever else needs doing goes here
});

When you need to remove the event listener, use the 'closure' reference, like so:

myDispatcher.removeEventListener("click", closure);

Obviously, this is an abstract example but using closures like this can be pretty useful. They do have drawbacks though, such as being less efficient than named methods. Another drawback is the fact that you actually have to store away a reference to the closure if you ever need it. Care must then be taken to preserve the integrity of that reference, just like with any other variable.

Thus, while the different syntax may have its uses, it's not always the best solution. It's an apples and oranges kind of thing.

like image 20
Marcus Stade Avatar answered Nov 03 '22 00:11

Marcus Stade


You can think of the function() keyword as a constructor, creating a new object (a closure) each time. Therefore, if you create the closure just for as a parameter and don't retain a reference anywhere, there's no way to get a hold of "the same" closure somewhere else.

The obvious solution is what you don't like, defining the function before using it. Of course, it can still be a full closure and not just a 'static-like' function. simply define it in the context you want, and assign it to a local variable.

like image 22
Javier Avatar answered Nov 03 '22 01:11

Javier