
Adding Listeners
The Event Phases
The way "in" is called the capture phase. The way "out" is called the bubbling phase. And when the event object is at the button1 object, this is called the target phase. The button1 object dispatched the event and also received the event, and so it is known as the target of the event. The other objects along the event flow would each in its turn be known as the currentTarget. Remember, we are discussing here strictly a click on button1. If anything else is clicked, the identities of the target and currentTarget objects change accordingly. So, in order to fully understand this, we have to confine our discussion to one event flow for now, which has five places where the event object flows to. button1 is the target and the other objects are all currentTarget(s).
We can add event listeners to each of these five places. The addEventListener method is a method of the EventDispatcher class. In Actionscript 3.0, MovieClips now have the EventDispatcher class in their inheritance chain, meaning that they are event dispatchers. So they can dispatch events, and they can have event listeners added to them. The Stage class is also descended from the EventDispatcher class, so it can also dispatch events and have event listeners added to it. So all I'm saying is that we can add event listeners to our stage, the menu, and our buttons.
The addEventListener method has five parameters. Here's the method's "signature:"
addEventListener( type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void
The first two parameters are the only ones that are required, so you'll often see listeners being added to objects using this short form:
button1.addEventListener(MouseEvent.CLICK, clickHandler);
This is saying that we want to listen for the CLICK event, that we want the event to call our handler function named clickHandler when the event happens, and that we don't want to listen for the capture phase. Even though we didn't specify that, that's what we will get because the default value for the third parameter, useCapture, is false, and we didn't supply an argument for it (the fourth and fifth parameters, which allow you to set listener priority and specify weak references, go a bit beyond the purposes of this article, but we will consider the useCapture parameter, because it has a lot to do with adding listeners to the different "places" along the event flow):
This diagram illustrates the phases of the event flow when button1 is clicked. We can add listeners to each of those five places, even add multiple listeners to each place if we want. For a click on button one, there are five choices for adding event listeners:
- We can add a listener to the stage for the capture phase
- We can add a listener to the menu for the capture phase
- We can add a listener to the button1 object for the target and bubbling phases
- We can add a listener to the menu for the target and bubbling phases
- We can add a listener to the stage for the target and bubbling phases
I want you to notice the choices for stage and menu: either capture phase or target and bubbling phases. The choice depends on the value you give the useCapture parameter. If you set the useCapture parameter to true, you have chosen the capture phase. If you set the useCapture parameter to false (or just accept the default value of false by not specifying), you have chosen target and bubbling. Take note that for events that bubble, there is no such thing as setting a listener for just the target phase or just the bubbling phase, as those two go together.
You may or may not find the capture phase especially useful. You would set an event for the capture phase in cases where you might want to conditionally stop the event flow from reaching its target. But you'll soon find out just how useful the target and bubbling phases can be! Note this well: The whole reason for having a bubbling phase is so that you can add event listeners to a container, and still detect events coming from the container's children (The capture phase is similar; it also lets you add a listener to a container and detect events coming from the children. But as noted, you probably won't use it as much).
So let's turn our attention to the starter fla file you downloaded (from page 1). Open it in Flash if you haven't already. Add this code to the end of the other code in frame 1:
menu.buttonMode = true;
button1.buttonMode = true;
button2.buttonMode = true;
This is just for appearance's sake--setting buttonMode to true will cause each of these objects to have a hand cursor when you hover it with the mouse. The stage doesn't have a buttonMode, so there's no way to get a hand cursor over it (nor would you really want to).
Let's start by adding a listener to the stage for the capture phase:
stage.addEventListener(MouseEvent.CLICK, clickHandler, true);
function clickHandler(event:MouseEvent):void {
trace("clicked");
}
In the following illustration, you can visually see that because a listener was added to the stage for the capture phase, it's as though a little note is made at that place in the event flow: call clickHandler:
Test the file with CTRL-ENTER. When you click on button1, you get the message "clicked" traced to the output panel. Even though you didn't add any listener to button1 at all--in fact the only listener has been added to the stage--it still fires when you click on button1. This is because of the event flow, of course! And now all the drawings, diagrams and the demo should be starting to make sense to you.
Try clicking on the other button (button2). The event fires! Click on the menu. The event fires! I want you to picture the event flow as you click each item (think of the demo swf from the preceding page). Click on the stage. The event does not fire. Why not? Because the event listener was added with useCapture set to true. When we click on the stage, the stage is the target. Since stage is the target and has no higher parent, there is no capture phase in this case. Do you remember from the demo that when you clicked on the stage, the event object only visited one place?
I digressed just a bit by having you try clicking on those other things, just to give you a feel for how it works. Now we'll get back to considering only clicks on button1. Let's add a listener to the menu next, also for the capturing phase:
menu.addEventListener(MouseEvent.CLICK, clickHandler, true);
You could write separate event handler functions, but you can also just re-use the same one, and that's what we'll do. And here's the visual for that:
Once again, run the file by pressing CTRL-ENTER. This time, when you click on button1, you will get the message "clicked" traced to the output window twice. This is because, as in the above diagram, adding those event listeners caused those objects to take note that when they got a click event, they should call the clickHandler function.
Next, let's add an event listener to button1 for the target and bubbling phases:
button1.addEventListener(MouseEvent.CLICK, clickHandler, false);
Remember that setting that third parameter to false means "don't use the capture phase, use the target and bubbling phases instead." Also, we could have just left off the third argument, because the default value for useCapture is false. I know I'm repeating myself, I just want to make sure everyone gets that. Since the target and bubbling phases are being specified, a click on the button will fire this listener too. It will fire in the target phase, when the event object is at the button itself:
Once again, run the file and click on button1. You will get the "clicked" message traced to the output window three times. Anyone detecting a pattern here? Let's go ahead and add the other listeners to the stage and the menu for the target and bubbling phases:
menu.addEventListener(MouseEvent.CLICK, clickHandler, false);
stage.addEventListener(MouseEvent.CLICK, clickHandler, false);
Now our listeners are defined in all five places:
All the code we've added so far should look like this (the lines that add event listeners can appear in any order, and above or below the event handler function, it doesn't matter):
stage.addEventListener(MouseEvent.CLICK, clickHandler, true);
function clickHandler(event:MouseEvent):void {
trace("clicked");
}
menu.addEventListener(MouseEvent.CLICK, clickHandler, true);
button1.addEventListener(MouseEvent.CLICK, clickHandler, false);
menu.addEventListener(MouseEvent.CLICK, clickHandler, false);
stage.addEventListener(MouseEvent.CLICK, clickHandler, false);
Test the movie again. Click the button. Not surprisingly, you will get the "clicked" message in the output window five times. When we add an event listener to the menu or the stage and specify the target and bubbling phases, we are in both cases adding the event listener to a container. So when we specify the target and bubbling phases, we are saying that we want to listen for events that happen to the children, too. I'll say it again: The whole reason for having a bubbling phase is so that you can add event listeners to a container, and still detect events coming from the container's children.
Now imagine a menu like ours with, say, ten buttons instead of two. Imagine how handy it will be to just add one event listener to the container menu, instead of each and every individual button. I can almost hear you asking "But how could you make the individual buttons do different things?" We will explore that question, among other things, on the next page. I know this has been a rather long page with a lot of theory and not that much action, but it was necessary to lay this groundwork and get a firm understanding of the event flow. On the next and following pages, we're going start putting it to some really cool uses!

