AS3: Custom Events
I've traveled far and wide (ok, not really) to find what I consider to be a good way to use custom events in ActionScript 3. Normally when dispatching events I like to pass in custom parameters that can be retrieved by the handler which I can then use in my code. I had some trouble fumbling around in AS3 to figure out what the best way to do this would be and have read numerous blog posts by a lot of people talking about coercion errors and the likes. I think my solution is a pretty good one and I certainly plan on using it myself. Here is the code of CustomEvent:
-
/**
-
* @author Matt Przybylski [http://www.reintroducing.com]
-
* @version 1.0
-
*/
-
-
package com.reintroducing.events
-
{
-
import flash.events.Event;
-
-
public class CustomEvent extends Event
-
{
-
//- PRIVATE & PROTECTED VARIABLES -------------------------------------------------------------------------
-
-
-
-
//- PUBLIC & INTERNAL VARIABLES ---------------------------------------------------------------------------
-
-
public static const DEFAULT_NAME:String = "com.reintroducing.events.CustomEvent";
-
-
// event constants
-
public static const ON_TEST_CASE:String = "onTestCase";
-
-
public var params:Object;
-
-
//- CONSTRUCTOR -------------------------------------------------------------------------------------------
-
-
public function CustomEvent($type:String, $params:Object, $bubbles:Boolean = false, $cancelable:Boolean = false)
-
{
-
super($type, $bubbles, $cancelable);
-
-
this.params = $params;
-
}
-
-
//- PRIVATE & PROTECTED METHODS ---------------------------------------------------------------------------
-
-
-
-
//- PUBLIC & INTERNAL METHODS -----------------------------------------------------------------------------
-
-
-
-
//- EVENT HANDLERS ----------------------------------------------------------------------------------------
-
-
-
-
//- GETTERS & SETTERS -------------------------------------------------------------------------------------
-
-
-
-
//- HELPERS -----------------------------------------------------------------------------------------------
-
-
public override function clone():Event
-
{
-
return new CustomEvent(type, this.params, bubbles, cancelable);
-
}
-
-
public override function toString():String
-
{
-
return formatToString("CustomEvent", "params", "type", "bubbles", "cancelable");
-
}
-
-
//- END CLASS ---------------------------------------------------------------------------------------------
-
}
-
}
Then, when using it in an FLA, you would do this:
-
import com.reintroducing.events.CustomEvent;
-
-
var evt:CustomEvent = new CustomEvent(CustomEvent.ON_TEST_CASE, {param1: "first param", param2: "second param"});
-
-
this.addEventListener(CustomEvent.ON_TEST_CASE, doTestCase);
-
this.dispatchEvent(evt);
-
-
function doTestCase($e:CustomEvent):void
-
{
-
trace("TYPE: " + $e.type + "\nTARGET: " + $e.target + "\nFIRST CUSTOM PARAM: " + $e.params.param1 + "\nSECOND CUSTOM PARAM: " + $e.params.param2);
-
trace($e.toString());
-
}
Alternately, you can write the dispatch line like so, but I find the above cleaner and easier to read:
-
this.dispatchEvent(new CustomEvent(CustomEvent.ON_TEST_CASE, {param1: "first param", param2: "second param"}));
This technique allows you to pass an object when writing your event which you can then retrieve in the handler by calling $e.params.whateverParam. This is very similar to how I would handle events and parameters I passed in with AS2 and I like this approach. It is clear and concise to me and it works well.
For those who use FDT3, I've included an XML file titled FDT3EventTemplate.xml which you can import into your Templates in the FDT preferences in Eclipse. This allows you to simply create a new class file, type in event and press ctrl+space (cmd+space on Mac) and WABAM! Like magic, it populates the custom event of your name right in front of your eyes. Remember to change the line that has YOUR_EVENT_CONSTANT to whatever your event's constant(s) is(are).
If you found this post useful, please consider leaving a comment, subscribing to the feed, or making a small donation.
12 Comments
I have implemented a similar solution in my recent project and really found it cool with those hashes like in ruby.
But the drawback is the lack of typechecking, and some times it can be a pain not be able to do the checks at compile time, don't you think?
I seems to tip back and fourth between the dynamic and the more static typed approach, not really knowing what to like ![]()
This is true, and I thought of this when making it Jacob. But as a personal solution and because I use eclipse/fdt, i wanted to be able to just add a template to it and not have much changes to make when i pull up an Event that has been created by my template. Personally, I always look back at the parameters I pass and know what their datatypes are, or you can always cast them when you take them out of the params object in your event handler.
I'd be interested in seeing what you came up with. Can you post your code? I think if you use the tags in the comments they should work. the tags are [ as ] and [ / as ] to close it up (without the spaces).
[...] its button actions. The MenuButtonEvent is just following my Event template that I outlined here and it allows me to dispatch an event when the menu button is clicked which is what the Main class [...]
I'll take it without mystery meat parameters stuffed into an anonymous generic object, and stick with typing and hinting. Anonymous objects seem to defeat much of the purpose of having the stronger typing to reduced mysterious code errors due to typos, imo.
For most custom events you can set the additional base event properties inside the constructor. For cases where you want to change that for each event dispatched, then you can match the base method signature and bite the bullet and just set the properties manually afterwards.
package test {
import flash.events.Event;
public class CustChangeEvent extends Event {
public static const CHANGE:String = "EVENT_CUST_CHANGE";
public var custId:int;
public var custName:String;
public function CustChangeEvent( type:String, custId:int, custName:String ) {
super( type );
this.custId = custId;
this.custName = custName;
}
// don't forget to override clone
}
}
// usage
var myEvent:CustChangeEvent = new CustChangeEvent( CustChangeEvent.CHANGE, 11, "exorcyze" );
myobject.dispatchEvent( myEvent );
Mike,
Yes, that is how I originally planned on doing it. 2 reasons why I (personally) didn't:
1) I use FDT templates ALL the time and it's easier for me to just throw in a template and put in the event constant and be done with it.
2) I'm typically not very careless when keeping track of my parameters in my events and I don't mind going back to look at them.
I realize that they aren't strongly typed and that may not be the best solution (and who knows, maybe one day ill convince myself to go back and change it to how you present it), but for now i have had no issues with it whatsoever and plan to keep using it until i do ![]()
[...] ContactFormEvent class which allows me to dispatch events in AS3 with custom parameters based on my AS3 Custom Events model. PLAIN TEXT [...]
hi, i was just thinking, what happens to the 'params' object every time you dispatch a new custom event - it never clears from memory? an instance of the class is created, with the object hard referenced, will it ever be garbage collected?
trent, thats a very good question and to be honest i don't know the answer, but i imagine it would be treated just as any other custom param you pass into a custom event in the same fashion. i've actually started to go the more strongly typed route and defined every param in my custom events recently so that i could get code hinting and all that. youll notice i do that in my SliderUI class if you grabbed that.
Please help me!!! I need to dispatch the event from inside a private function into the timeline.
I'd really tried to find a solution for this and I think your explanation is not so far from my needs. Please, please, I have to deliver a job on tuesday and I'm stuck on this!
the dispatching of the event is as follows (if we're using the CustomEvent as in this example):
-
import com.reintroducing.events.CustomEvent;
-
-
var evt:CustomEvent = new CustomEvent(CustomEvent.ON_TEST_CASE, {param1: "first param", param2: "second param"});
-
-
this.dispatchEvent(evt);
Then, on your timeline on the frame you want to receive the event, you'd do this:
-
import com.reintroducing.events.CustomEvent;
-
-
this.addEventListener(CustomEvent.ON_TEST_CASE, doTestCase);
-
-
function doTestCase($e:CustomEvent):void
-
{
-
trace("TYPE: " + $e.type + "\nTARGET: " + $e.target + "\nFIRST CUSTOM PARAM: " + $e.params.param1 + "\nSECOND CUSTOM PARAM: " + $e.params.param2);
-
trace($e.toString());
-
}
That should give you what you're looking for Joao.











Nice!
I actually prefer writing it out like the below just because its shorter code.
dispatchEvent(new CustomEvent(CustomEvent.ON_TEST_CASE, {param1: "first param", param2: "second param"}));
I have also read that its good practice to have a clone method in your CustomEvent class:
public override function clone():Event
{
return new CustomEvent(type, params);
}
That way you create a copy of that particular Event object... maybe so you could modify the variables without altering the original Event you received.