AS3: Custom Events

Download Example Files

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:

Actionscript:
  1. /**
  2. * @author Matt Przybylski [http://www.reintroducing.com]
  3. * @version 1.0
  4. */
  5.  
  6. package com.reintroducing.events
  7. {
  8.     import flash.events.Event;
  9.    
  10.     public class CustomEvent extends Event
  11.     {
  12. //- PRIVATE & PROTECTED VARIABLES -------------------------------------------------------------------------
  13.  
  14.        
  15.        
  16. //- PUBLIC & INTERNAL VARIABLES ---------------------------------------------------------------------------
  17.        
  18.         public static const DEFAULT_NAME:String = "com.reintroducing.events.CustomEvent";
  19.        
  20.         // event constants
  21.         public static const ON_TEST_CASE:String = "onTestCase";
  22.        
  23.         public var params:Object;
  24.        
  25. //- CONSTRUCTOR -------------------------------------------------------------------------------------------
  26.    
  27.         public function CustomEvent($type:String, $params:Object, $bubbles:Boolean = false, $cancelable:Boolean = false)
  28.         {
  29.             super($type, $bubbles, $cancelable);
  30.            
  31.             this.params = $params;
  32.         }
  33.        
  34. //- PRIVATE & PROTECTED METHODS ---------------------------------------------------------------------------
  35.        
  36.        
  37.        
  38. //- PUBLIC & INTERNAL METHODS -----------------------------------------------------------------------------
  39.    
  40.        
  41.    
  42. //- EVENT HANDLERS ----------------------------------------------------------------------------------------
  43.    
  44.        
  45.    
  46. //- GETTERS & SETTERS -------------------------------------------------------------------------------------
  47.    
  48.        
  49.    
  50. //- HELPERS -----------------------------------------------------------------------------------------------
  51.    
  52.         public override function clone():Event
  53.         {
  54.             return new CustomEvent(type, this.params, bubbles, cancelable);
  55.         }
  56.        
  57.         public override function toString():String
  58.         {
  59.             return formatToString("CustomEvent", "params", "type", "bubbles", "cancelable");
  60.         }
  61.    
  62. //- END CLASS ---------------------------------------------------------------------------------------------
  63.     }
  64. }

Then, when using it in an FLA, you would do this:

Actionscript:
  1. import com.reintroducing.events.CustomEvent;
  2.  
  3. var evt:CustomEvent = new CustomEvent(CustomEvent.ON_TEST_CASE, {param1: "first param", param2: "second param"});
  4.  
  5. this.addEventListener(CustomEvent.ON_TEST_CASE, doTestCase);
  6. this.dispatchEvent(evt);
  7.        
  8. function doTestCase($e:CustomEvent):void
  9. {
  10.     trace("TYPE: " + $e.type + "\nTARGET: " + $e.target + "\nFIRST CUSTOM PARAM: " + $e.params.param1 + "\nSECOND CUSTOM PARAM: " + $e.params.param2);
  11.     trace($e.toString());
  12. }

Alternately, you can write the dispatch line like so, but I find the above cleaner and easier to read:

Actionscript:
  1. 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.

49 Comments

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.

There is a clone method in the class I posted.

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):

Actionscript:
  1. import com.reintroducing.events.CustomEvent;
  2.  
  3. var evt:CustomEvent = new CustomEvent(CustomEvent.ON_TEST_CASE, {param1: "first param", param2: "second param"});
  4.  
  5. this.dispatchEvent(evt);

Then, on your timeline on the frame you want to receive the event, you'd do this:

Actionscript:
  1. import com.reintroducing.events.CustomEvent;
  2.  
  3. this.addEventListener(CustomEvent.ON_TEST_CASE, doTestCase);
  4.  
  5. function doTestCase($e:CustomEvent):void
  6. {
  7.     trace("TYPE: " + $e.type + "\nTARGET: " + $e.target + "\nFIRST CUSTOM PARAM: " + $e.params.param1 + "\nSECOND CUSTOM PARAM: " + $e.params.param2);
  8.     trace($e.toString());
  9. }

That should give you what you're looking for Joao.

I'm having trouble getting my custom event to trigger in parent/sibling objects when dispatched from a child. I've followed your instructions quite carefully. Am I missing something?
Thanks πŸ™‚

edward,
what does your code look like and please explain your hierarchy for the clips. Thanks.

hi,

1st thks for sharing ...
I see that we set Params in the same place as dispatch !!
wht if we want to set Params in another asFile and dispatch on another one ? that why we use dispatchCustom event <--
thks in advance...

Reda,
You'd have to keep track of what you want to dispatch at a central point somewhere in your application and then have a way to pull those variables into the dispatch call so that it knows what you want to add to the params.

Hi matt,

thank you for the insightful post.
However i'm still left with a question or two.

Say i dispatch params/an object this way from a child. How would i get the information across to another child?

For example: I have a thumbnail class that listens for a mouse click on a thumbnail and then dispatches an event. How do i get that to another child that handles the loading of the clicked item?

Kevin,
Can you give me a little bit more detail about your classes/objects? The thumbnail has its own class and dispatches an even on click inside of it's class with params you're setting, correct? then the other child you're speaking of, is this a child of the thumbnail or a child of a clip that contains the thumbnail and this other child? just a bit more would be helpful to try and troubleshoot this.

Main.as instantiates the Thumbnails.as and AssetLoader.as.
Thumbnails.as handles the xml and generates a list with thumbnails. Attached to the thumbs nails is the custom event listener. Main.as attaches a listener for the custom event on the Thumbnails instance and then i pass the information that comes with it to the Assetloader.

I got it working in the mean time the way i describe, but is there a way to bypass having to send the information to the parent? And just straight from the thumbnails class to the loader class?

Kevin,
From what I'm understanding of your structure, there isn't a way to bypass that because the AssetLoader doesn't know that the Thumbnail exists and vice versa. The Main is what ties it all together and where the listener is as well as the instance of the AssetLoader so that would be the best course of action.

Alright so keeping it in the class that holds it together is the way to go.

What's a good/better way to delegate these kinds of things? Or would i be headed more towards the MVC pattern typed thing?

Kevin,
You'd probably be headed towards MVC. I worked a bit with Cairngorm in the past and did some stuff like this where it would dispatch the event up like 50 things (thats an exaggeration) and it kind of irked me a bit to have to do that. i normally work the same way you just did, but there are probably more "design pattern" friendly ways to do this that i just don't care to implement πŸ˜› I think hardcore coders who have been coding since the olden days would probably kick my ass for that statement, but i do what works for me and the project and am happy with it.

Alright, thanks a lot for the input, certainly helpful. πŸ˜€

Hi Matt,
thank you for your tutorial. i have followed a few of these Custom event tutorials, yours just makes sense and i click with it. thanks

and now my questions:

1. in your custom event class
public static const DEFAULT_NAME:String = "com.reintroducing.events.CustomEvent"; what is the purpose of this line? -assume conflict events with same name? how do u use it,

2. this custom event class, will it have all the possible static variable names that i need to listen to declared here?

3.what is the purpose of the clone function as described, how do you use it?

4.i recently see a lot of the character "$" in parameters being received in a function, what is that and its purpose

5.i wrote a pimped up version of delegate class which allowed passing of parameters with function calls,
in as3 i want to call a function with mouse events but i want to add parameters (but i cant use my as2 class), would i do it like this using your class:

*snippet of code*

var evt:CustomEvent = new CustomEvent(CustomEvent.ON_TEST_CASE, {param1: "first param", param2: "second param"});

_button.addEventListener(MouseEvent.MOUSE_UP, button_Release);

public function button_Release(){
this.addEventListener(CustomEvent.ON_TEST_CASE, doTestCase);
this.dispatchEvent(evt);
}

function doTestCase(){
trace("hello");
}

so u use it like a proxy function?

clarklin,
1) this was a way of identifying the class with the toString() method when you trace it out but it was also something I used to do because of a habit I got into while using Cairngorm. I now use the getSpecifiedClassName() method instead in my toString to trace it out and no longer use the DEFAULT_NAME constants in my classes.

2) yes, put all your static constants in the class that have to do with that event type and you could re-use them wherever you need to.

3) the clone function needs to be present for the custom events to be fired off because it extends the Event class. if you didn't have the clone method present, you would not be able to pass in your params and you would get errors in the flash player.

4) I use the dollar sign in parameters so that when using them in my methods i know that its the parameter that i'm using, not a local or class variable. this is just a preference, not necessary for everyone to use. its just a habit/practice of mine that helps me differentiate.

5) you should probably define the addEventListener for the custom event after the button listener, not inside of your button_Release method, so you dont try to add the listener multiple times if it is clicked multiple times. then just dispatch the event like you have in the button_Release method and in the doTestCase() method, make sure you define doTestCase($evt:CustomEvent) so that you can then grab the param1 and param2 properties that you have set in the custom event class, by doing $evt.params.param1, etc.

I have to be honest though, I've started to do more strictly typed events lately and have gotten away from doing it like this just because I want to have the code hinting for properties in my events. This was a great solution when I was first starting out in AS3 and it was good because it was how I was used to doing stuff in AS2, but as I get more and more into AS3 I prefer doing the strongly typed way more.

hi Matt thanks for your reply, really helpful in me wrapping my mind around it, when you talk about strictly typed events?
does that mean u use multiple classes, one class= one idea = one event class? or you mean your parameters dont use an object, because that way you cant make use of type of parameters,

if you got an example of the new way u do things that'd be great, else thanks for all your help cos already that was a big hurdle that i just jumped.

clark

clarklin,
exactly, my parameters no longer use an object rather each one is strictly typed in the class. this would be an example of that:

Actionscript:
  1. package com.reintroducing.events
  2. {
  3.     import flash.events.Event;
  4.    
  5.     /**
  6.      * @author Matt Przybylski [http://www.reintroducing.com]
  7.     * @version 1.0
  8.     */
  9.     public class VideoEvent extends Event
  10.     {
  11. //- PRIVATE & PROTECTED VARIABLES -------------------------------------------------------------------------
  12.  
  13.        
  14.        
  15. //- PUBLIC & INTERNAL VARIABLES ---------------------------------------------------------------------------
  16.        
  17.         // event constants
  18.         public static const LOAD_PROGRESS:String = "onVideoLoadProgress";
  19.         public static const LOADED:String = "onVideoLoaded";
  20.         public static const METADATA_LOADED:String = "onMetaDataLoaded";
  21.         public static const PLAY:String = "onPlay";
  22.         public static const PAUSE:String = "onPause";
  23.         public static const UNPAUSE:String = "onUnpause";
  24.         public static const PROGRESS:String = "onVideoProgress";
  25.         public static const FINISHED:String = "onVideoFinished";
  26.         public static const RESIZE:String = "onResize";
  27.        
  28.         public var loadProgress:Number;
  29.         public var duration:Number;
  30.         public var time:Number;
  31.         public var percent:Number;
  32.        
  33. //- CONSTRUCTOR -------------------------------------------------------------------------------------------
  34.    
  35.         public function VideoEvent($type:String, $loadProgress:Number = 0, $duration:Number = 0, $time:Number = 0, $percent:Number = 0, $bubbles:Boolean = false, $cancelable:Boolean = false)
  36.         {
  37.             super($type, $bubbles, $cancelable);
  38.            
  39.             this.loadProgress = $loadProgress;
  40.             this.duration = $duration;
  41.             this.time = $time;
  42.             this.percent = $percent;
  43.         }
  44.  
  45. //- PRIVATE & PROTECTED METHODS ---------------------------------------------------------------------------
  46.        
  47.        
  48.        
  49. //- PUBLIC & INTERNAL METHODS -----------------------------------------------------------------------------
  50.    
  51.        
  52.    
  53. //- EVENT HANDLERS ----------------------------------------------------------------------------------------
  54.    
  55.        
  56.    
  57. //- GETTERS & SETTERS -------------------------------------------------------------------------------------
  58.    
  59.        
  60.    
  61. //- HELPERS -----------------------------------------------------------------------------------------------
  62.    
  63.         public override function clone():Event
  64.         {
  65.             return new VideoEvent(type, this.loadProgress, this.duration, this.time, this.percent, bubbles, cancelable);
  66.         }
  67.        
  68.         public override function toString():String
  69.         {
  70.             return formatToString("VideoEvent", "loadProgress", "duration", "time", "percent", "type", "bubbles", "cancelable");
  71.         }
  72.    
  73. //- END CLASS ---------------------------------------------------------------------------------------------
  74.     }
  75. }

then when dispatching the event, you do something like this:

Actionscript:
  1. var evt:VideoEvent = new VideoEvent(VideoEvent.LOAD_PROGRESS, progressHere, durationHere, timeHere, percentHere);
  2. dispatchEvent(evt);

Keep in mind though where the progressHere, durationHere, etc, those are optional since they are defined as 0 in the parameters of the event which gives you some nice flexibility and strict typing when using the events.

hope that helps.

Hey matt
thanks for this, i'm gonna work through this, i get it now, just need to set it in concrete,
Everybody, Matt is a very helpful person he is a Custom Events Sensei. with this last post, everyone should understand how it works.
thank you
clark

lol clarklin, i'm no sensei, but glad it helped. good luck.

[...] share the one I came up with recently for a project I’m currently working on. There are several excellent articlesΒ that should get you up and running with the idea of custom events, here’s [...]

Sorry if I'm repeating something someones already said here, but I was interested in the debate between the generic object and strong typing parameters.

My solution to this so far is to use a generic params:Object, but populate it with a simple value object that I create.

So:

public class SimpleCustomVO
{
// class members
public var prop1:String
public var prop2:String
public var prop3:Array
}

And then:

public function someEventDispatched():void
{
var params:SimpleCustomVO = new SimpleCustomVO();
params.prop1 = "foo";
params.prop2 = "bar";
params.prop3 = ["foo", "bar"]

dispatchEvent(new CustomEvent(CustomEvent.TYPE, params);
}

When I catch the event, I can go back and strong type the params object to my SimpleCustomVO like so:

protected function customEventListener( e : CustomEvent ):void
{
var simpleCustomVO:SimpleCustomVO = e.params as SimpleCustomVO;

var str:String = simpleCustomVO.prop1;
}

In FDT, now we can use a generic object and still get auto-complete. WHee!

Also. Wanted to say thanks for the template. Came across this page quite awhile ago. Not only was it really handy for creating custom events, it also helped me understand the whole concept in as3 much more clearly.

So thanks! ^_^

@Aubrey: That is certainly one way to get around the auto completion. while its a good solution (if you want the AC in FDT) purists will probably argue that its not the way it should be done. i'm not a purist so if that makes you happy and works for you, then why not? πŸ˜› and thanks for the kind words, its really appreciated and glad i could help.

oh and i use VOs all the time, probably one of the two useful things I picked up while being forced to use cairngorm a while back (what a mess that framework is).

You're right, probably not the most "purist" solution ever. But at least its not a generic object, haha. VO is really simple and I can just pass it in. When I have more than 2 weeks and one shot to build something I will do it the "proper" way. ^_^

[...] good examples; 1. http://www.learningactionscript3.com/2008/11/11/passing-arguments-with-events/ 2. http://evolve.reintroducing.com/2007/10/23/as3/as3-custom-events/ Categories: Uncategorized Tags: ActionScript Comments (0) Trackbacks (0) Leave a comment [...]

Hi Matt

I came across your blog and this post while learning about Custom Events for as3, which I was absolutely unaware of.

I implemented your class, and it worked perfectly within a class that reads a collection of rss feeds, one after another, when dispatching an END_OF_FEED CustomEvent ..

Then I thought it would be really neat to use these CustomEvents from the document class, to listen to events generated at classes, like the RSS Manager, so the main class 'knows' when all data has been read, parsed, and is ready to be displayed. It worked really nicely as well.

But I came down to a bump. The AIR app i'm working on needs to connect to a SQLite ddbb before obtaining the RSS feeds collection. So I did exactly the same methods that I used for the RSSManager class, and it didn't work.

My Main.as class has this call:
sqlMan = new SQLManager(); sqlMan.addEventListener(CustomEvent.SQL_CONNECTED,onSqlConnection);

While on a function in my SQLManager.as (extends Sprite) class i do
this.dispatchEvent(new CustomEvent(CustomEvent.SQL_CONNECTED, {aRSS:aRSS}));

Am I doing something wrong here? Do I need to set my class to extend something else (and why would it work on the RSSManager.as which also extends Sprite)?

Thanx for any info regarding this...
This was already a marvelous piece of info.

@qborreda: Glad the classes helped! As for your issue, your code seems solid and I don't see any reason why it wouldn't work as you have it written. Are you just not getting anything in the onSqlConnection if you do a trace in that method? Extending sprite is the right thing to do because Sprite can dispatch events, so there isn't an issue there. There has to be something else in your code that is tripping something up. Make sure the function that dispatches the event is not being called before the slqMan instance is being created as well. other than that, you got me...

Hi, I need your help. I want to have a videoplaylist and the player in separate SWF. I want to have the player on the top of the page and the videoplaylist all the way down the page. When the user select aa video, the player has to play it. How I am going to dispatch the mouse click event and pass the url of the video.

Please help!
Thank you!

@Addis: You'll have to look at the LocalConnection class to trigger something from one SWF to the other.

Kevin,

Is it possible for you to demonstrate me how to write the code for communicationg a videoplaylist swf with a player SWF? Just show me what to do?

Thank you!

Matt,

Thank you for quick response. But How am I going to do that? Am going to write both send and receive methodes in one action script file? Please it would be nice if you show me some code. Is this mean we can not do it by dispatching a custom event? Have done this kinds of project where the playlist and the player in a separate swfs? Please help!!

@Addis: Unfortunately I don't have time to write the code for you, but if you google LocalConnection or even read the documentation in Flash help you should be able to get a clear idea of how it works and what you'll need to do.

the info for dispatching the events, how do i get it out of the main file and into a class?

Hi Matt, this helping as I struggle my way into the world that is AS3. What I am trying to do is pass variables from one class to another, or call a function from one class via another... and I just can't seem to get it... tried a few different things. I am working on a game where I have a class for my bullets, which move by using the enter frame Event. I need to call a function which can check their positions against the positions of 'enemies' on the screen, but this needs to be done in the parent... Im really struggling with AS3 so any help would be appreciated.
Matt.

[...] addEventListener for ALL events (Comtaste Consulting | Enterprise RIA consulting and development) AS3: Custom Events joeberkovitz.com » Moment of Weakness: Weak Event Listeners Can Be Dangerous Chapter 2: [...]

i am not getting a single line from this code

[...] [...]

Leave a comment

(required)

(required)