This is something that you are probably going to kick yourself over when you see how easy it is! ....
The very words "event dispatcher" and "dispatching events" sound so technical that they may strike fear into your very heart! You may think, "I'll never understand all of that stuff, it's too hard." For something that sounds so intimidating, though, dispatching your own custom events turns out to be so incredibly simple in its basic form, as you will see.
I'm sure you probably aren't hearing this anywhere else. Neither am I. All I can figure is that the people that know this stuff don't want you to know how simple it really is, for whatever reason. But I do want you to know, because I think it has the potential to super-charge the way you write programs!
The first thing you need is a reason to dispatch a custom event. This was kind of hard for me to fathom at first. I understood the built-in events, like the user pressing a key or clicking a button, or even more system-oriented type events, like when a file finishes loading. But I just had a hard time thinking of what a custom event might signify. Like, what would be an example of a useful, custom event? I just couldn't think of one.
Well, there are many cases where you might want to dispatch your own custom events, and, in fact, it turns out to be the answer to a question a lot of people are always asking about classes: "How can I get my classes to communicate with each other?" Because event dispatching (and the related listening) is an excellent way to make objects communicate.
Nowadays, I have a less difficult time conceiving of a custom event. Any time you want an object to let other objects know when something has happened to it (for example, the value of one of its variables has changed), you can dispatch an event. I am going to use a very simple example that you should be very familiar with.
Suppose that you have a MovieClip instance that plays an animation on its timeline, and you want to make something else happen in the main movie when that MovieClip instance is done playing. Let's create a simple AS3 fla file that illustrates this.
Open a new Flash file (Actionscript 3.0). Using the oval tool, draw a circle. Select the whole thing, and press F8 to convert it to a symbol. Name the symbol "Ball," choose MovieClip type, and click OK. Next, delete the instance from the stage. The "Ball" symbol you just created should still be in the library. So make sure the symbol wasn't deleted, just the instance.
Next go to the Insert menu, and choose "New Symbol." Type in "Animated Ball" for the symbol's name. Once again, choose the MovieClip type. Click OK. You are now in the edit mode for the Animated Ball MovieClip. Drag an instance of Ball out to the stage. Align it to the left and top by setting its X and Y both to 0 in the properties panel (optionally use the align panel with the "to stage" button selected, if you prefer).
Click frame 40 of Layer 1 of the timeline. Press F6 to create a new keyframe. Click on the ball to select it. In the properties panel, give the ball on this frame an X value of 400. Now, right-click the frames in the timeline somewhere between the two keyframes. Choose "create motion tween" from the context menu (CS4 users choose "create classic tween"). This Animated Ball MovieClip is just a very simple example, which will serve to illustrate the principle. The actual MovieClip you use in an actual project might be way more elaborate, and the event or events that you dispatch might have totally unrelated purposes. But what we are going to do here is to dispatch an event that lets us know that the Animated Ball MovieClip is done playing.
Name this layer "ball." Now create a new layer above this one, and name it "actions." Click on frame 40 of the actions layer and press F6 to insert a keyframe. Click on frame 1 of the actions layer. Press F9 to get the actions panel. Type in a stop() command:
stop();
Now click on frame 40 of the actions layer. Type in the following commands in the actions panel:
stop(); dispatchEvent(new Event("done"));
At this point, your screen should look something like this:

Now the "insides" of the Animated Ball MovieClip is finished. Remember, all instances of this MovieClip will inherit its own copy of this same timeline, including the code.
Next, go back to Scene 1. Drag two instances of the Animated Ball MovieClip to the stage. Place them close to the left hand side of the stage. Give them instance names of clip1 and clip2. Double click the layer they are on and name it "clips." Add a new layer and name it "actions." Now your stage should look like this:

Click on the first frame of the actions layer and press F9 for the actions panel. Type in the following:
stage.addEventListener(MouseEvent.CLICK, stageClicked); function stageClicked(event:MouseEvent):void { stage.removeEventListener(MouseEvent.CLICK, stageClicked); clip1.play(); }
With the above code in place, test the movie. When you click anywhere on the stage, clip1 plays its timeline. Also, the event listener is removed so that you can only click the stage once.
Now we are going to add the code that adds an event listener to clip1 for our custom "done" event. So add the following to the actions panel, after the existing code there:
clip1.addEventListener("done", clip1Done); function clip1Done(event:Event):void { clip2.play(); }
Test the movie. You will see that when you click the stage, clip1 plays its timeline, as before. However, this time, we have added an event listener to clip1 that listens for the custom "done" event. So, when clip1's timeline plays, when it gets to the last frame of its timeline, the code there dispatches an event. And now we have, in the main timeline, a listener function that is listening for that event. Because of our custom event listener, when clip1 is done playing its timeline, clip2 begins playing its timeline.
So this is the part I want you to get: the object that dispatches the event is the same object that you want to add the event listener to.
I had the hardest time "getting" this at first, because I had some preconceived ideas about how event listeners might work. I thought that any object could dispatch (broadcast) an event, and that any other object could listen for it. That much is actually true--the part I was missing was that the object that wants to listen must register with the object doing the dispatching. So let's identify the players here. In the case of our custom event, what is the object that wants to listen? It is the main timeline of our application. What is the listener? It is the clip1Done function. And of course, the event broadcaster is the clip1 instance.
What we have basically done by adding a listener is to cause clip1 to make an internal note to itself. It might read something like this: "When I dispatch my 'done' event, I should call the clip1Done function, which is located on the main timeline." This internal note is actually a list (in programming terms, it's an array) of listener functions to call when the event is dispatched.
Notice that we are adding an event listener for a "done" type event. What identifies the type of the event is just simply a string of text! When we add an event listener, as long as we specify the exact same string of text as the one specified in the event dispatch, it all works! There is nothing magical or mystical about the string we used here, "done". Any string of text would have worked just as well. We get to make it up!
Nor is there anything magical or mystical about the strings that are being used in Flash and Actionscript's built-in events. They are all just strings! And other programmers have just made them up! For example, let's take MouseEvent.CLICK. In this case, CLICK is just simply a public static constant of the MouseEvent class. That just means that it is just a variable--a storage space that holds the sting "click." You can prove this to yourself by just tracing out its value:
trace(MouseEvent.CLICK); //click
The same is true for all of the built-in events. So you can see that you could just as easily listen for the string "click" when you add an event listener to an object for a MouseEvent.CLICK event. So it's just a convention in programming to always use the constant instead of just the string. One reason for this is error checking. Since the addEventListener and dispatchEvent functions don't care what string of text you use (as clearly demonstrated by our custom event), dispatching and listening for "clik" would be just as valid as "click." But in the case of the MouseEvent.CLICK, the string being dispatched is "click", and you can't in this case change the string being dispatched. So if you listen for "clik" your code will fail, but you won't get an error message telling you why. However, if you always use the constant, and you make a typo, like "MouseEvent.CLIK," you will get an error message that the MouseEvent class doesn't define any such constant.
Getting back to our custom "done" event, let's add an event listener to clip2 also. Since clip1 and clip2 are both instances of the same MovieClip symbol, they both dispatch the "done" event at the end of their timeline. That means that we can add an event listener for the "done" event to either one, or both, or neither. It's all our choice. Add these lines to the code:
clip2.addEventListener("done", clip2Done); function clip2Done(event:Event):void { clip1.gotoAndStop(1); clip2.gotoAndStop(1); stage.addEventListener(MouseEvent.CLICK, stageClicked); }
With this new code, when clip2 is done playing its timeline, it dispatches the "done" event, our code listens for it, and the clip2Done function is run. This function tells both clip instances to go back to their first frame again, and the last line reinstates the CLICK listener for the stage. So this function just sets it all up again, so that the whole process can just repeat.
There is a beauty to this whole approach that you will come to appreciate as you begin to use it in your own projects. Let's suppose that we had used a different approach, and, at the end of its timeline, the Animated Ball MovieClip, rather than dispatching an event, called a function in the main timeline instead. While this would be entirely possible, it makes the Animated Ball MovieClip not nearly as reusable in another project, because it makes it depend on the existance of a certain function with a certain name in the main timeline. Every time you used it you would have to look into the insides of it, to see what is the name of the function that it wants to call. Then, if you didn't have this function in place, the very presence of an instance of this clip in your project will cause an error when it plays to the end of its timeline, because it will be looking for that specific function.
In contrast, using the event dispatching approach, an event is dispatched at the end of the timeline. The object doing the event dispatching neither knows, nor cares, whether any other objects are actually doing any listening. If there are no listeners defined for the event, it doesn't make any difference. The event is dispatched harmlessly. No errors are generated. But at the same time, this approach makes it very nice and flexible for outside (client) code. Any number of listeners can to be added to the object, and all that needs to be known is the type of the event. This, incidentally, is known as decoupling, and it is a way of reducing dependencies between objects.
What I have written into this article is all the information you need to know to dispatch your own custom events. I have purposely kept it simple, because I wanted you to see how simple it really is at the heart of it. So, I didn't get into classes. I didn't get into extending the Event class, where you can define your own custom properties, and so pass custom information to your event listeners.
I also didn't get into events that bubble. I said earlier that the object that wants to listen must register with the object doing the dispatching. There is an exception to this rule, however. In the case of events that bubble, the event listener can be added to a parent or grand-parent (that is, a display list "ancestor") of the object doing the dispatching. To dispatch an event and make it a bubbling event, though, you have to set the second parameter of the Event class's constructor to true when you are dispatching the event:
dispatchEvent(new Event("done", true));
The things that I didn't get into are things that I figure you can go on to learn on your own. Or perhaps I'll deal with them in a follow-up tutorial. Hopefully this will give you a solid foundation on which to build your future knowledge of this subject. I've seen many other tutorials out there that deal with the more complicated aspects of custom events, but I really haven't seen one that reduced it to its essentials, with a really easy example, and I hope that this has helped fill that void.
Jody,
Thanks for the tutorial. It helped to clarify s few issues for me that I hope to be able to put to good use.
thanks so much for this tutorial, it's exactly what i was looking for. and it looks surprisingly simple, but i'm still not understanding one aspect of it. When you write "done", how does flash know you mean "when this movie clip is done playing"? you said, it is just a name and could be anything, but i don't see anywhere in the code in your tutorial that defines "done" to flash. What am I missing?
Hey shaftbond, thanks for joining the site!
Flash really doesn't know the movie clip is done playing. That part is taken care of by virtue of the fact that you are dispatching the event from the very last frame. The event doesn't get dispatched until the last frame plays, because frame code is executed as the "playhead" reads it. So where you place the code that dispatches the event is the key element there.
I was making the point that what gets dispatched is just a string of text, so the word "done" could be anything. It is meaningless to Flash, but the word "done" makes sense to us. What is important is that the string that is dispatched matches the string that is being listened for. You should definitely download the sample file and examine it. It should start making sense to you.
ugh..i'm an idiot. I guess I was so excited to learn how to do this, I was reading too fast and missed where the dispatchEvent code went. :) I get it now.
Jody- thanks for the site. I'm just starting into actionscript 3 and your tutorials are extremely helpful and well written.
Hi,
I get the general idea here but, of course, the first time I try to use it in a file of my own I can't make it work.
I get the concept in your tutorial, When Clip1 completes its tween it calls for clip2 to run, then both clips return to frame 1. I made the attached FLA as a small tutorial for myself to see if I could use the concept. The way it's supposed to work is hen you click on the stage the moon sinks below the horizon (clip1) and then the sun rises (clip2).
I kept your code. I replaced the Ball clips with one of the moon sinking and one of the sun rising.
I can only get the moon to sink, the sunrise clip won't run. Any ideas off the top of your head?
Thanks,
Brian
Brian,
It sounds like you may have neglected to dispatch the event at the end of the timeline of each clip. You have to click the last frame of the timeline, and you have to press F6 to insert a keyframe there. Then you have to press F9 to get the actions panel, and add the line that dispatches the event:
stop();
dispatchEvent(new Event("done"));
(without an inserted keyframe, this code is going to look like it's going on the last frame, but it won't be--it will be going on whatever the previous keyframe was-- so that's one possible thing to watch for).
Alternatively, load my example file into flash and study it some more. The script navigator is off to the left hand side of the actions panel. I use it a LOT myself, especially with other peoples' files. With the script navigator you can easily see every place in the file that has any script. You will see where my fille dispatches the "done" event on the last frame of the animated Ball Movie Clip. Make sure that yours does likewise, and you should be good to go.
Jody
That was it, Jody. I didn't dispatch the Done function on the final keyframe of the timeline in my animated moon MC.
Thanks for the tutorial.
Jingledale
I have read hundreds of explanations about how to dispathEvent() and they all complicate it so much that is never clear what you really need to do it. I love that way of explaining things in the simplest way possible (and it should be that way), that's the different between a good teacher and a bad one. I already knew how it works but you filled all the little blank spots that i had left.
thanks.
Thank you, Ross_AS3 for the compliment! That really made my day.
Hi Jody,
I'm new flash (only in AS 3.0). I think that by this function:
stage.addEventListener(MouseEvent.CLICK, stageClicked);
function stageClicked(event:MouseEvent):void {
stage.removeEventListener(MouseEvent.CLICK, stageClicked);
myMovieClip.play();
}
Do you know any way to make component?
maxflash,
Sorry, I don't really understand the question, or what it has to do with event dispatching.
Hi Jody, I just wanted to first say thanks for putting this site together. I have asked my fair share of forum questions on actionscript.org among other places. You have answered some of them and your replies tend to be a great help compared to some of the other replies I have gotten.
Anyhow, regarding the Event Dispatcher: I have had a hard time understanding it. One use of the Event Dispatcher that I really need to wrap my head around is how to use it for navigation. If I have idle, over, down and out states for my buttons within my navigation as well as intro and outro animations for whatever content, I do not understand how to play the outro animations when a new button is hit and before the new contents intro animation appears. The only way I know how to change content is to put all the content in one big MC and slide it to the x and y coordinate locations when the button is hit.
I have searched high and low for a tutorial explaining this specifically, but have had no luck. I suppose that this tutorial should help me, but I'm still pretty new at AS3 or any programming for that matter and I have a hard time using the information for a specific problem.
SO, I'm hoping that you might be able to help me get past this whether it be generously taking the time to explain it with specifics or maybe you know of a specific tutorial that already exists that you could point me to. Either of which I would be grateful for.
Thank you for your time.
Jeff