Using events

Using events in Flex is a two-step process. First, you write a function or class method, known as an event listener or event handler, that responds to events. The function often accesses the properties of the Event object or some other settings of the application state. The signature of this function usually includes an argument that specifies the event type being passed in.

The following example shows a simple event listener function that reports when a control triggers the event that it is listening for:

<?xml version="1.0"?>
<!-- events/SimpleEventHandler.mxml -->
<s:Application 
    xmlns:fx="http://ns.adobe.com/mxml/2009"    
    xmlns:mx="library://ns.adobe.com/flex/mx"     
    xmlns:s="library://ns.adobe.com/flex/spark"
    creationComplete="initApp();">

    <fx:Script>
        <![CDATA[
        import mx.controls.Alert;

        private function initApp():void {
            b1.addEventListener(MouseEvent.CLICK, myEventHandler);
        }

        private function myEventHandler(event:Event):void {
            Alert.show("An event occurred.");
        }
        ]]>
    </fx:Script>

    <s:Button id="b1" label="Click Me"/>

</s:Application>

The executing SWF file for the previous example is shown below:

As you can see in this example, you also register that function or class method with a display list object by using the addEventListener() method.

Most Flex controls simplify listener registration by letting you specify the listener inside the MXML tag. For example, instead of using the addEventListener() method to specify a listener function for the Button control’s click event, you specify it in the click attribute of the <mx:Button> tag:

<?xml version="1.0"?>
<!-- events/SimplerEventHandler.mxml -->
<s:Application 
    xmlns:fx="http://ns.adobe.com/mxml/2009"    
    xmlns:mx="library://ns.adobe.com/flex/mx"     
    xmlns:s="library://ns.adobe.com/flex/spark">
    
    <fx:Script>
        <![CDATA[
        import mx.controls.Alert;

        private function myEventHandler(event:Event):void {
            Alert.show("An event occurred.");
        }
        ]]>
    </fx:Script>

    <s:Button id="b1" label="Click Me" click="myEventHandler(event)"/>

</s:Application>

The executing SWF file for the previous example is shown below:

This is equivalent to the addEventListener() method in the previous code example. However, it is best practice to use the addEventListener() method. This method gives you greater control over the event by letting you configure the priority and capturing settings, and use event constants. In addition, if you use addEventListener() to add an event handler, you can use removeEventListener() to remove the handler when you no longer need it. If you add an event handler inline, you cannot call removeEventListener() on that handler.

Each time a control generates an event, Flex creates an Event object that contains information about that event, including the type of event and a reference to the dispatching control. To use the Event object, you specify it as a parameter in the event handler function, as the following example shows:

<?xml version="1.0"?>
<!-- events/EventTypeHandler.mxml -->
<s:Application 
    xmlns:fx="http://ns.adobe.com/mxml/2009"    
    xmlns:mx="library://ns.adobe.com/flex/mx"     
    xmlns:s="library://ns.adobe.com/flex/spark">

    <fx:Script>
        <![CDATA[
        import mx.controls.Alert;

        private function myEventHandler(e:Event):void {
            Alert.show("An event of type '" + e.type + "' occurred.");
        }
        ]]>
    </fx:Script>

    <s:Button id="b1" label="Click Me" click="myEventHandler(event)"/>

</s:Application>

The executing SWF file for the previous example is shown below:

If you want to access the Event object in an event handler that was triggered by an inline event, you must add the event keyword inside the MXML tag so that Flex explicitly passes it to the handler, as in the following:

<mx:Button id="b1" label="Click Me" click="myEventHandler(event)"/>

You are not required to use the Event object in a handler function. The following example creates two event handler functions and registers them with the events of a ComboBox control. The first event handler, openEvt(), takes no arguments. The second event handler, changeEvt(), takes the Event object as an argument and uses this object to access the value and selectedIndex of the ComboBox control that triggered the event.

<?xml version="1.0"?>
<!-- events/MultipleEventHandlers.mxml -->
<s:Application 
    xmlns:fx="http://ns.adobe.com/mxml/2009"    
    xmlns:mx="library://ns.adobe.com/flex/mx"     
    xmlns:s="library://ns.adobe.com/flex/spark">

    <s:layout> 
        <s:VerticalLayout/> 
    </s:layout>

    <fx:Script><![CDATA[
        private function openEvt():void {
            forChange.text="";
        }

        private function changeEvt(e:Event):void {
            forChange.text = 
            "Value: " + e.currentTarget.selectedItem + "\n" +
            "Index: " + e.currentTarget.selectedIndex;
        }
    ]]></fx:Script>

    <s:ComboBox open="openEvt()" change="changeEvt(event)">
        <s:dataProvider>
            <s:ArrayList>
                <fx:String>AK</fx:String>
                <fx:String>AL</fx:String>
                <fx:String>AR</fx:String>
            </s:ArrayList>
        </s:dataProvider>
    </s:ComboBox>

    <s:TextArea id="forChange" width="150" height="100"/>

</s:Application>

The executing SWF file for the previous example is shown below:

This example shows accessing the target property of the Event object. For more information, see Accessing the currentTarget property.

Specifying the Event object

You specify the object in a listener function’s signature as type Event, as the following example shows:

function myEventListener(e:Event):void { ... }

However, if you want to access properties that are specific to the type of event that was dispatched, you must instead specify a more specific event type, such as ToolTipEvent or KeyboardEvent, as the following example shows:

import mx.events.ToolTip 
function myEventListener(e:ToolTipEvent):void { ... }

In some cases, you must import the event’s class in your ActionScript block.

Most objects have specific events that are associated with them, and most of them can dispatch more than one type of event.

If you declare an event of type Event, you can cast it to a more specific type to access its event-specific properties. For more information, see Using event subclasses.

Accessing the currentTarget property

Event objects include a reference to the instance of the dispatching component (or target), which means that you can access all the properties and methods of that instance in an event listener. The following example accesses the id of the Button control that triggered the event:

<?xml version="1.0"?>
<!-- events/AccessingCurrentTarget.mxml -->
<s:Application
    xmlns:fx="http://ns.adobe.com/mxml/2009"    
    xmlns:mx="library://ns.adobe.com/flex/mx"     
    xmlns:s="library://ns.adobe.com/flex/spark">

    <fx:Script>
        <![CDATA[
            import mx.controls.Alert;

            private function myEventHandler(e:Event):void {
                Alert.show("The button '" + e.currentTarget.id + "' was clicked.");
            }
        ]]>
    </fx:Script>

    <s:Button id="b1" label="Click Me" click="myEventHandler(event)"/>

</s:Application>

The executing SWF file for the previous example is shown below:

You can access members of the currentTarget. If you do not cast the current target to a specific type, the compiler assumes that it is of type Object. Objects can have any property or method because the Object type is dynamic in ActionScript. Therefore, when accessing methods and properties of the currentTarget, it is best practice to cast currentTarget to whatever class you anticipate will dispatch that event. This gives you strong type checking at compile time, and helps avoid the risk of throwing a run-time error.

The following example casts the current target to a TextInput class before calling the selectRange() method, but does not cast it before trying to set the tmesis property. The tmesis property does not exist on the TextInput class. This illustrates that you will get a run-time error but not a compile-time error when you try to access members that don’t exist, unless you cast currentTarget to a specific type so that type checking can occur:

<?xml version="1.0"?>
<!-- events/InvokingOnCurrentTarget.mxml -->
<s:Application 
    xmlns:fx="http://ns.adobe.com/mxml/2009"    
    xmlns:mx="library://ns.adobe.com/flex/mx"     
    xmlns:s="library://ns.adobe.com/flex/spark"
    width="500">

    <fx:Script>
        <![CDATA[
        import mx.core.UIComponent;

        private function tiHandler(e:Event):void {
            /* 
            The following enforces type checking: 
            */
            TextInput(e.currentTarget).selectRange(0,3);

            /* 
            The following throws a run-time error but not a compile-time error: 
            e.currentTarget.tmesis = 4;
            */

            /*
            ... unless you cast it to the expected type like the following. Then
            the compiler throws an error.
            TextInput(e.currentTarget).tmesis = 4; 
            */
        }
        ]]>
    </fx:Script>

    <s:TextInput id="ti1" click="tiHandler(event)"
        text="When you click on this control, the first three characters are selected."
        width="400"/>

</s:Application>

The executing SWF file for the previous example is shown below:

You could also cast currentTarget to UIComponent or some other more general class that still has methods of display objects. That way, if you don’t know exactly which control will dispatch an event, at least you can ensure there is some type checking.

You can also access methods and properties of the target property, which contains a reference to the current node in the display list. For more information, see About the target and currentTarget properties.

Registering event handlers

There are several strategies that you can employ when you register event handlers with your Flex controls:

  1. Define an event handler inline. This binds a call to the handler function to the control that triggers the event.

    <?xml version="1.0"?>
    <!-- events/SimplerEventHandler.mxml -->
    <s:Application 
        xmlns:fx="http://ns.adobe.com/mxml/2009"    
        xmlns:mx="library://ns.adobe.com/flex/mx"     
        xmlns:s="library://ns.adobe.com/flex/spark">
        
        <fx:Script>
            <![CDATA[
            import mx.controls.Alert;
    
            private function myEventHandler(event:Event):void {
                Alert.show("An event occurred.");
            }
            ]]>
        </fx:Script>
    
        <s:Button id="b1" label="Click Me" click="myEventHandler(event)"/>
    
    </s:Application>

    The executing SWF file for the previous example is shown below:

    In this example, whenever the user clicks the Button control, Flex calls the myClickHandler() function.

    For more information on defining event handlers inline, see Defining event listeners inline.

  2. Use the addEventListener() method, as follows:

    <?xml version="1.0"?>
    <!-- events/SimpleEventHandler.mxml -->
    <s:Application 
        xmlns:fx="http://ns.adobe.com/mxml/2009"    
        xmlns:mx="library://ns.adobe.com/flex/mx"     
        xmlns:s="library://ns.adobe.com/flex/spark"
        creationComplete="initApp();">
    
        <fx:Script>
            <![CDATA[
            import mx.controls.Alert;
    
            private function initApp():void {
                b1.addEventListener(MouseEvent.CLICK, myEventHandler);
            }
    
            private function myEventHandler(event:Event):void {
                Alert.show("An event occurred.");
            }
            ]]>
        </fx:Script>
    
        <s:Button id="b1" label="Click Me"/>
    
    </s:Application>

    The executing SWF file for the previous example is shown below:

    As with the previous example, whenever the user clicks the Button control, Flex calls the myClickHandler() handler function. However, registering your event handlers using this method provides more flexibility. You can register multiple components with this event handler, add multiple handlers to a single component, or remove the handler. For more information, see Using the addEventListener() method.

  3. Create an event handler class and register components to use the class for event handling. This approach to event handling promotes code reuse and lets you centralize event handling outside your MXML files. For more information on creating custom event handler classes, see Creating event handler classes.

Defining event listeners inline

The simplest method of defining event handlers in applications is to point to a handler function in the component’s MXML tag. To do this, you add any of the component’s events as a tag attribute followed by an ActionScript statement or function call.

You add an event handler inline using the following syntax:

<s:tag_nameevent_name="handler_function"/>

For example, to listen for a Button control’s click event, you add a statement in the <mx:Button> tag’s click attribute. If you add a function, you define that function in an ActionScript block. The following example defines the submitForm() function as the handler for the Button control’s click event:

<fx:Script><![CDATA[ 
    function submitForm():void { 
        // Do something. 
    } 
]]></fx:Script> 
<s:Button label="Submit" click="submitForm();"/>

Event handlers can include any valid ActionScript code, including code that calls global functions or sets a component property to the return value. The following example calls the trace() global function:

<s:Button label="Get Ver" click="trace('The button was clicked');"/>

There is one special parameter that you can pass in an inline event handler definition: the event parameter. If you add the event keyword as a parameter, Flex passes the Event object and inside the handler function, you can then access all the properties of the Event object.

The following example passes the Event object to the submitForm() handler function and specifies it as type MouseEvent:

<?xml version="1.0"?>
<!-- events/MouseEventHandler.mxml -->
<s:Application 
    xmlns:fx="http://ns.adobe.com/mxml/2009"    
    xmlns:mx="library://ns.adobe.com/flex/mx"     
    xmlns:s="library://ns.adobe.com/flex/spark">

    <fx:Script>
        <![CDATA[
        import mx.controls.Alert;
    
        private function myEventHandler(event:MouseEvent):void {
            // Do something with the MouseEvent object.
            Alert.show("An event of type '" + event.type + "' occurred.");     
        }
        ]]>
    </fx:Script>

    <s:Button id="b1" label="Click Me" click="myEventHandler(event)"/>

</s:Application>

The executing SWF file for the previous example is shown below:

It is best practice to include the event keyword when you define all inline event listeners and to specify the most stringent Event object type in the resulting listener function (for example, specify MouseEvent instead of Event).

You can use the Event object to access a reference to the target object (the object that dispatched the event), the type of event (for example, click), or other relevant properties, such as the row number and value in a list-based control. You can also use the Event object to access methods and properties of the target component, or the component that dispatched the event.

Although you will most often pass the entire Event object to an event listener, you can just pass individual properties, as the following example shows:

<?xml version="1.0"?>
<!-- events/PropertyHandler.mxml -->
<s:Application
    xmlns:fx="http://ns.adobe.com/mxml/2009"    
    xmlns:mx="library://ns.adobe.com/flex/mx"     
    xmlns:s="library://ns.adobe.com/flex/spark">

    <fx:Script>
        <![CDATA[
        import mx.controls.Alert;
    
        private function myEventHandler(s:String):void {
            Alert.show("Current Target: " + s);
        }
        ]]>
    </fx:Script>

    <s:Button id="b1" label="Click Me" click="myEventHandler(event.currentTarget.id)"/>

</s:Application>

The executing SWF file for the previous example is shown below:

Registering an event listener inline provides less flexibility than using the addEventListener() method to register event listeners. The drawbacks are that you cannot set the useCapture or priority properties on the Event object and that you cannot remove the listener once you add it.

Using the addEventListener() method

The addEventListener() method lets you register event listener functions with the specified control or object. The following example adds the myClickListener() function to the b1 instance of a Button control. When the user clicks b1, Flex calls the myClickListener() method:

b1.addEventListener(MouseEvent.CLICK, myClickListener);

The addEventListener() method has the following signature:

componentInstance.addEventListener( 
    event_type:String, 
    event_listener:Function, 
    use_capture:Boolean, 
    priority:int, 
    weakRef:Boolean 
)

The event_type argument is the kind of event that this component dispatches. This can be either the event type String (for example, “click” or “mouseOut”) or the event type static constant (such as MouseEvent.CLICK or MouseEvent.MOUSE_OUT). This argument is required.

The constants provide an easy way to refer to specific event types. You should use these constants instead of the strings that they represent. If you misspell a constant name in your code, the compiler catches the mistake. If you instead use strings and make a typographical error, it can be harder to debug and could lead to unexpected behavior.

You should use the constants wherever possible. For example, when you are testing to see whether an Event object is of a certain type, use the following code:

if (myEventObject.type == MouseEvent.CLICK) {/* your code here */}

Do not use the following code:

if (myEventObject.type == "click") {/* your code here */}

The event_listener argument is the function that handles the event. This argument is required.

The use_capture parameter of the addEventListener() method lets you control the phase in the event flow in which your listener will be active. It sets the value of the useCapture property of the Event object. If useCapture is set to true, your listener is active during the capturing phase of the event flow. If useCapture is set to false, your listener is active during the targeting and bubbling phases of the event flow, but not during the capturing phase. The default value is determined by the type of event, but is false in most cases.

To listen for an event during all phases of the event flow, you must call addEventListener() twice, once with the useCapture parameter set to true, and again with use_capture set to false. This argument is optional. For more information, see Capturing phase.

The priority parameter sets the priority for that event listener. The higher the number, the sooner that event handler executes relative to other event listeners for the same event. Event listeners with the same priority are executed in the order that they were added. This parameter sets the priority property of the Event object. The default value is 0, but you can set it to negative or positive integer values. If several event listeners are added without priorities, the earlier a listener is added, the sooner it is executed. For more information on setting priorities, see Event priorities.

The weakRef parameter provides you with some control over memory resources for listeners. A strong reference (when weakRef is false) prevents the listener from being garbage collected. A weak reference (when weakRef is true) does not. The default value is false.

When you add a listener function and that function is invoked, Flex implicitly creates an Event object for you and passes it to the listener function. You must declare the Event object in the signature of your listener function.

If you add an event listener by using the addEventListener() method, you are required to declare an event object as a parameter of the listener_function, as the following example shows:

b1.addEventListener(MouseEvent.CLICK, performAction);

In the listener function, you declare the Event object as a parameter, as follows:

public function performAction(e:MouseEvent):void { 
    ... 
}

The following example defines a new handler function myClickListener(). It then registers the click event of the Button control with that handler. When the user clicks the button, Flex calls the myClickHandler() function.

<?xml version="1.0"?>
<!-- events/AddEventListenerExample.mxml -->
<s:Application 
    xmlns:fx="http://ns.adobe.com/mxml/2009"    
    xmlns:mx="library://ns.adobe.com/flex/mx"     
    xmlns:s="library://ns.adobe.com/flex/spark"
    initialize="createListener()">

    <fx:Script>
        <![CDATA[
            import mx.controls.Alert;
            private function createListener():void {
                b1.addEventListener(MouseEvent.CLICK, myClickHandler, false, 0);
            }

            private function myClickHandler(e:MouseEvent):void {
                Alert.show("The button was clicked.");
            }
        ]]>
    </fx:Script>

    <s:Button label="Click Me" id="b1"/>

</s:Application>

The executing SWF file for the previous example is shown below:

Using addEventListener() inside an MXML tag

You can add event listeners with the addEventListener() method inline with the component definition. The following Button control definition adds the call to the addEventListener() method inline with the Button control’s initialize property:

<?xml version="1.0"?>
<!-- events/CallingAddEventListenerInline.mxml -->
<s:Application 
    xmlns:fx="http://ns.adobe.com/mxml/2009"    
    xmlns:mx="library://ns.adobe.com/flex/mx"     
    xmlns:s="library://ns.adobe.com/flex/spark">

    <fx:Script>
        <![CDATA[
            import mx.controls.Alert;

            private function myClickHandler(event:Event):void {
               Alert.show("The button was clicked.");
            }
        ]]>
    </fx:Script>

    <s:Button id='b1' 
        label="Click Me" 
        initialize='b1.addEventListener(MouseEvent.CLICK, myClickHandler, false, 1);'
    />

</s:Application>

The executing SWF file for the previous example is shown below:

This is the equivalent of defining the event handler inline. However, defining a handler by using the addEventListener() method rather than setting click="handler_function" lets you set the value of the useCapture and priority properties of the Event object. Furthermore, you cannot remove a handler added inline, but when you use the addEventListener() method to add a handler, you can call the removeEventListener() method to remove that handler.

Using nested inner functions as event listeners

Rather than passing the name of an event listener function to the addEventListener() method, you can define an inner function (also known as a closure).

In the following example, the nested inner function is called when the button is clicked:

<?xml version="1.0"?>
<!-- events/AddingInnerFunctionListener.mxml -->
<s:Application 
    xmlns:fx="http://ns.adobe.com/mxml/2009"    
    xmlns:mx="library://ns.adobe.com/flex/mx"     
    xmlns:s="library://ns.adobe.com/flex/spark"
    creationComplete="initApp()">

    <fx:Script>
        <![CDATA[    
        import mx.controls.Alert;

        private function initApp():void {
            b1.addEventListener("click", 
                function(e:Event):void {
                    Alert.show("The button was clicked.");        
                }
            );        
        }
        ]]>
    </fx:Script>

    <s:Button id='b1' label="Click Me"/>

</s:Application>

The executing SWF file for the previous example is shown below:

Function closures are created any time a function is executed apart from an object or a class. They retain the scope in which they were defined. This creates interesting results when a function is passed as an argument or a return value into a different scope.

For example, the following code creates two functions: foo(), which returns a nested function named rectArea() that calculates the area of a rectangle, and bar(), which calls foo() and stores the returned function closure in a variable named myProduct. Even though the bar() function defines its own local variable x (with a value of 2), when the function closure myProduct() is called, it retains the variable x (with a value of 40) defined in function foo(). The bar() function therefore returns the product of the numbers in the TextInput controls, rather than 8.

<?xml version="1.0"?>
<!-- events/FunctionReturnsFunction.mxml -->
<s:Application 
    xmlns:fx="http://ns.adobe.com/mxml/2009"    
    xmlns:mx="library://ns.adobe.com/flex/mx"     
    xmlns:s="library://ns.adobe.com/flex/spark"
    creationComplete="foo()">

    <s:layout> 
        <s:VerticalLayout/> 
    </s:layout>

    <fx:Script>
        <![CDATA[    
        [Bindable]
        private var answer:String;

        private function foo():Function {
            var x:int = int(ti1.text);
            function rectArea(y:int):int { // function closure defined
                return x * y;
            } 
            return rectArea;
        }

        private function bar():void {
            var x:int = 2; // ignored
            var y:int = 4; // ignored
            var myProduct:Function = foo();
            answer = myProduct(int(ti2.text)); // function closure called
        }
    
        ]]>
    </fx:Script>

    <mx:Form width="107">
        <mx:FormItem label="X">
            <mx:TextInput id="ti1" text="10" width="37" textAlign="right"/>
        </mx:FormItem>
        <mx:FormItem label="Y" width="71">
            <mx:TextInput id="ti2" text="20" width="38" textAlign="right"/>
        </mx:FormItem>
        <mx:Label id="label1" text="{answer}" width="71" textAlign="right"/>
    </mx:Form>

    <s:Button id='b1' label="Compute Product" click="bar()"/>
    
</s:Application>

The executing SWF file for the previous example is shown below:

If the listener that you pass to addEventListener() method is a nested inner function, you should not pass true for the useWeakReference argument. For example:

addEventListener("anyEvent", 
    function(e:Event) { /* My listener function. */ }, 
    false, 0, true);

In this example, passing true as the last argument can lead to unexpected results. To Flex, an inner function is actually an object, and can be freed by the garbage collector. If you set the value of the useWeakReference argument to true, as shown in the previous example, there are no persistent references at all to the inner function. The next time the garbage collector runs, it might free the function, and the function will not be called when the event is triggered.

If there are other references to the inner function (for example, if you saved it in another variable), the garbage collector will not free it.

Regular class-level member functions are not subject to garbage collection; as a result, you can set the value of the useWeakReference argument to true and they will not be garbage collected.

Removing event handlers

It is a good idea to remove any handlers that will no longer be used. This removes references to objects so that they can be targeted for garbage collection. You can use the removeEventListener() method to remove an event handler that you no longer need. All components that can call addEventListener() can also call the removeEventListener() method. The syntax for the removeEventListener() method is as follows:

componentInstance.removeEventListener(event_type:String, listener_function:Function, use_capture:Boolean)

For example, consider the following code:

myButton.removeEventListener(MouseEvent.CLICK, myClickHandler);

The event_type and listener_function parameters are required. These are the same as the required parameters for the addEventListener() method.

The use_capture parameter is also identical to the parameter used in the addEventListener() method. Recall that you can listen for events during all event phases by calling addEventListener() twice: once with use_capture set to true, and again with it set to false. To remove both event listeners, you must call removeEventListener() twice: once with use_capture set to true, and again with it set to false.

You can remove only event listeners that you added with the addEventListener() method in an ActionScript block. You cannot remove an event listener that was defined in the MXML tag, even if it was registered using a call to the addEventListener() method that was made inside a tag attribute.

The following sample application shows what type of handler can be removed and what type cannot:

<?xml version="1.0"?>
<!-- events/RemoveEventListenerExample.mxml -->
<s:Application 
    xmlns:fx="http://ns.adobe.com/mxml/2009"    
    xmlns:mx="library://ns.adobe.com/flex/mx"     
    xmlns:s="library://ns.adobe.com/flex/spark"
    initialize="createHandler(event)">

    <s:layout> 
        <s:VerticalLayout/> 
    </s:layout>

    <fx:Script>
        <![CDATA[
        import mx.controls.Alert;

        private function createHandler(e:Event):void {
            b1.addEventListener(MouseEvent.CLICK, myClickHandler);
        }

        private function removeMyHandlers(e:Event):void {
            /* Remove listener for b1's click event because it was added
            with the addEventListener() method. */
            b1.removeEventListener(MouseEvent.CLICK, myClickHandler);

            /* Does NOT remove the listener for b2's click event because it
            was added inline in an MXML tag. */           
            b2.removeEventListener(MouseEvent.CLICK, myClickHandler);
        }

        private function myClickHandler(e:Event):void {
            Alert.show("The button was clicked.");
        }
        ]]>
    </fx:Script>

    <s:Button id="b1" label="Click Me"/>
    <s:Button label="Click Me Too" id="b2" click="myClickHandler(event)"/>
    <s:Button label="Remove Event Listeners" id="b3" click="removeMyHandlers(event)"/>

</s:Application>

The executing SWF file for the previous example is shown below:

Creating event handler classes

You can create an external class file and use the methods of this class as event handlers. Objects themselves cannot be event handlers, but methods of an object can be. By defining one class that handles all your event handlers, you can use the same event handling logic across applications, which can make your MXML applications more readable and maintainable.

To create a class that handles events, you usually import the flash.events.Event class. You also usually write an empty constructor. The following ActionScript class file calls the Alert control’s show() method whenever it handles an event with the handleAllEvents() method:

// events/MyEventHandler.as

package { // Empty package.

    import flash.events.Event;
    import mx.controls.Alert;

    public class MyEventHandler {
        public function MyEventHandler() {
            // Empty constructor.
        }

        public function handleAllEvents(event:Event):void {
            Alert.show("Some event happened.");
        }
    }
}

In your MXML file, you declare a new instance of MyEventHandler and use the addEventListener() method to register its handleAllEvents() method as a handler to the Button control’s click event, as the following example shows:

<?xml version="1.0"?>
<!-- events/CustomHandler.mxml -->
<s:Application 
    xmlns:fx="http://ns.adobe.com/mxml/2009"    
    xmlns:mx="library://ns.adobe.com/flex/mx"     
    xmlns:s="library://ns.adobe.com/flex/spark"
    initialize="createHandler()">

    <fx:Script>
        <![CDATA[
            private var myListener:MyEventHandler = new MyEventHandler();

            private function createHandler():void {
                b1.addEventListener(MouseEvent.CLICK, myListener.handleAllEvents);
            }
        ]]>
    </fx:Script>

    <s:Button label="Submit" id="b1"/>

</s:Application>

The executing SWF file for the previous example is shown below:

The best approach is to define the event handler’s method as static. When you make the event handler method static, you are not required to instantiate the class inside your MXML application. The following createHandler() function registers the handleAllEvents() method as an event handler without instantiating the MyStaticEventHandler class:

<?xml version="1.0"?>
<!-- events/CustomHandlerStatic.mxml -->
<s:Application 
    xmlns:fx="http://ns.adobe.com/mxml/2009"    
    xmlns:mx="library://ns.adobe.com/flex/mx"     
    xmlns:s="library://ns.adobe.com/flex/spark"
    initialize="createHandler()">

    <fx:Script>
        <![CDATA[
            private function createHandler():void {
                b1.addEventListener(MouseEvent.CLICK, MyStaticEventHandler.handleAllEvents);
            }
        ]]>
    </fx:Script>

    <s:Button label="Submit" id="b1"/>

</s:Application>

The executing SWF file for the previous example is shown below:

In the class file, you just add the static keyword to the method signature:

// events/MyStaticEventHandler.as

package { // Empty package.

    import flash.events.Event;
    import mx.controls.Alert;

    public class MyStaticEventHandler {
        public function MyStaticEventHandler() {
            // Empty constructor.
        }

        public static function handleAllEvents(event:Event):void {
            Alert.show("Some event happened.");
        }
    }
}

Store your event listener class in a directory in your source path. You can also store your ActionScript class in the same directory as your MXML file, although Adobe does not recommend this.

Defining multiple listeners for a single event

You can define multiple event handler functions for a single event in two ways. When defining events inside MXML tags, you separate each new handler function with a semicolon. The following example adds the submitForm() and debugMessage() functions as handlers of the click event:

<?xml version="1.0"?>
<!-- events/MultipleEventHandlersInline.mxml -->
<s:Application     
    xmlns:fx="http://ns.adobe.com/mxml/2009"    
    xmlns:mx="library://ns.adobe.com/flex/mx"     
    xmlns:s="library://ns.adobe.com/flex/spark">

    <s:layout> 
        <s:VerticalLayout/> 
    </s:layout>

    <fx:Script><![CDATA[
        [Bindable]
        private var s:String = "";
  
        private function submitForm(e:Event):void {
            // Handle event here.
            s += "The submitForm() method was called. ";
        }
        private function debugMessage(e:Event):void {
            // Handle event here.
            s += "The debugMessage() method was called. ";
        }
    ]]></fx:Script>
  
    <s:Button id="b1" 
        label="Do Both Actions"
        click='submitForm(event); debugMessage(event);' 
    />
    <s:Label id="l1" text="{s}"/>
    
    <s:Button id="b2" label="Reset" click="s='';"/>
    
</s:Application>

The executing SWF file for the previous example is shown below:

For events added with the addEventListener() method, you can add any number of handlers with additional calls to the addEventListener() method. Each call adds a handler function that you want to register to the specified object. The following example registers the submitForm() and debugMessage() handler functions with b1’s click event:

<?xml version="1.0"?>
<!-- events/MultipleEventHandlersAS.mxml -->
<s:Application 
    xmlns:fx="http://ns.adobe.com/mxml/2009"    
    xmlns:mx="library://ns.adobe.com/flex/mx"     
    xmlns:s="library://ns.adobe.com/flex/spark"
    creationComplete="createHandlers(event)">

    <s:layout> 
        <s:VerticalLayout/> 
    </s:layout>

    <fx:Script><![CDATA[
        [Bindable]
        private var s:String = "";

        public function createHandlers(e:Event):void {
            b1.addEventListener(MouseEvent.CLICK, submitForm);
            b1.addEventListener(MouseEvent.CLICK, debugMessage);
        }

        private function submitForm(e:Event):void {
            // Handle event here.
            s += "The submitForm() method was called. ";
            
        }

        private function debugMessage(e:Event):void {
            // Handle event here.
            s += "The debugMessage() method was called. ";            
        }

    ]]></fx:Script>

    <s:Button id="b1" label="Do Both Actions"/>

    <s:Label id="l1" text="{s}"/>
    
    <s:Button id="b2" label="Reset" click="s='';"/>

</s:Application>

The executing SWF file for the previous example is shown below:

You can mix the methods of adding event handlers to any component; alternatively, you can add handlers inline and with the addEventListener() method. The following example adds a click event handler inline for the Button control, which calls the performAction() method. It then conditionally adds a second click handler to call the logAction() method, depending on the state of the CheckBox control.

<?xml version="1.0"?>
<!-- events/ConditionalHandlers.mxml -->
<s:Application 
    xmlns:fx="http://ns.adobe.com/mxml/2009"    
    xmlns:mx="library://ns.adobe.com/flex/mx"     
    xmlns:s="library://ns.adobe.com/flex/spark"
    initialize="initApp(event)">

    <s:layout> 
        <s:VerticalLayout/> 
    </s:layout>

    <fx:Script>
        <![CDATA[
            import mx.controls.Alert;

            private function initApp(e:Event):void {
               cb1.addEventListener(MouseEvent.CLICK, handleCheckBoxChange);
               b1.addEventListener(MouseEvent.CLICK, logAction);
            }

            private function handleCheckBoxChange(e:Event):void {
               if (cb1.selected) {
                    b1.addEventListener(MouseEvent.CLICK, logAction);
                    ta1.text += "Added log listener." + "\n";
                } else {
                    b1.removeEventListener(MouseEvent.CLICK, logAction);
                    ta1.text += "Removed log listener." + "\n";
                }
            }

            private function performAction(e:Event):void {
                Alert.show("You performed the action.");
            }

            private function logAction(e:Event):void {
                ta1.text += "Action performed: " + e.type + ".\n";
            }
        ]]>
    </fx:Script>

    <s:Button label="Perform Action" id="b1" click="performAction(event)"/>
    <s:CheckBox id="cb1" label="Log?" selected="true"/>
    <s:TextArea id="ta1" height="200" width="300"/>

</s:Application>

The executing SWF file for the previous example is shown below:

You can set the order in which event listeners are called by using the priority parameter of the addEventListener() method. You cannot set a priority for a listener function if you added the event listener using MXML inline. For more information on setting priorities, see Event priorities.

Registering a single listener with multiple components

You can register the same listener function with any number of events of the same component, or events of different components. The following example registers a single listener function, submitForm(), with two different buttons:

<?xml version="1.0"?>
<!-- events/OneHandlerTwoComponentsInline.mxml -->
<s:Application     
    xmlns:fx="http://ns.adobe.com/mxml/2009"    
    xmlns:mx="library://ns.adobe.com/flex/mx"     
    xmlns:s="library://ns.adobe.com/flex/spark">

    <s:layout> 
        <s:VerticalLayout/> 
    </s:layout>

    <fx:Script>
        <![CDATA[
        import mx.controls.Alert;

        private function submitForm(e:Event):void {
            // Handle event here.
            Alert.show("Current Target: " + e.currentTarget.id);
        }

        ]]>
    </fx:Script>

    <s:Button id="b1" 
        label="Click Me"
        click="submitForm(event)"/>

    <s:Button id="b2" 
        label="Click Me, Too"
        click="submitForm(event)"/>
        
</s:Application>

The executing SWF file for the previous example is shown below:

When you use the addEventListener() method to register a single listener to handle the events of multiple components, you must use a separate call to the addEventListener() method for each instance, as the following example shows:

<?xml version="1.0"?>
<!-- events/OneHandlerTwoComponentsAS.mxml -->
<s:Application 
    xmlns:fx="http://ns.adobe.com/mxml/2009"    
    xmlns:mx="library://ns.adobe.com/flex/mx"     
    xmlns:s="library://ns.adobe.com/flex/spark"
    creationComplete="createHandlers(event)">

    <s:layout> 
        <s:VerticalLayout/> 
    </s:layout>

    <fx:Script>
        <![CDATA[
        import mx.controls.Alert;

        public function createHandlers(e:Event):void {
            b1.addEventListener(MouseEvent.CLICK, submitForm);
            b2.addEventListener(MouseEvent.CLICK, submitForm);
        }

        private function submitForm(e:Event):void {
            // Handle event here.
            Alert.show("Current Target: " + e.currentTarget.id);
        }
        ]]>
    </fx:Script>

    <s:Button id="b1" label="Click Me"/>

    <s:Button id="b2" label="Click Me, Too"/>

</s:Application>

The executing SWF file for the previous example is shown below:

When doing this, you should add logic to the event listener that processes the type of event. The event target (or object that dispatched the event) is added to the Event object for you. No matter what triggered the event, you can conditionalize the event processing based on the target or type properties of the Event object. Flex adds these two properties to all Event objects.

The following example registers a single listener function (myEventHandler()) to the click event of a Button control and the click event of a CheckBox control. To detect what type of object called the event listener, the listener checks the className property of the target in the Event object in a case statement.

<?xml version="1.0"?>
<!-- events/ConditionalTargetHandler.mxml -->
<s:Application 
    xmlns:fx="http://ns.adobe.com/mxml/2009"    
    xmlns:mx="library://ns.adobe.com/flex/mx"     
    xmlns:s="library://ns.adobe.com/flex/spark"
    creationComplete="initApp()">

    <s:layout> 
        <s:VerticalLayout/> 
    </s:layout>

    <fx:Script>
        <![CDATA[
        import mx.controls.Alert;
    
        public function initApp():void {
            button1.addEventListener(MouseEvent.CLICK, myEventHandler);
            cb1.addEventListener(MouseEvent.CLICK, myEventHandler);
        }

        public function myEventHandler(event:Event):void {
            switch (event.currentTarget.className) {
                case "Button":
                    // Process Button click.
                    Alert.show("You clicked the Button control.");
                    break;
                case "CheckBox":
                    // Process CheckBox click.
                    Alert.show("You clicked the CheckBox control.");
                    break;
            }
        }
        ]]>
    </fx:Script>

    <s:Button label="Click Me" id="button1"/>
    <s:CheckBox label="Select Me" id="cb1"/>

</s:Application>

The executing SWF file for the previous example is shown below:

Passing additional parameters to listener functions

You can pass additional parameters to listener functions depending on how you add the listeners. If you add a listener with the addEventListener() method, you cannot pass any additional parameters to the listener function by arbitrarily adding new parameters to the function signature. The default listener function can declare only a single argument, the Event object (or one of its subclasses).

For example, the following code throws an error because the clickListener() method expects two arguments:

<fx:Script> 
    public function addListeners():void { 
        b1.addEventListener(MouseEvent.CLICK,clickListener); 
    } 
    public function clickListener(e:MouseEvent, a:String):void { ... } 
</fx:Script> 
<mx:Button id="b1"/>

Because the second parameter of the addEventListener() method is a function, you can define that function and pass the event object plus any additional parameters through to a different handler. The following example creates a new function in the addEventListener() method, add two parameters to the new handler’s call, and then handles all of the parameters in the myClickListener() method.

<?xml version="1.0" encoding="utf-8"?>
<!-- events/CustomListenerFunction.mxml -->
<s:Application 
    xmlns:fx="http://ns.adobe.com/mxml/2009"    
    xmlns:mx="library://ns.adobe.com/flex/mx"     
    xmlns:s="library://ns.adobe.com/flex/spark"
    creationComplete="initApp(event)">

    <s:layout> 
        <s:VerticalLayout/> 
    </s:layout>

    <fx:Script>
        <![CDATA[
            private var specialParam1:String;
            private var specialParam2:String = "42";

            private function initApp(e:Event):void {
                assignSpecialParam(e);
                
                /* Change the value of specialParam whenever the user changes it 
                   in the TextInput and clicks the button. */
                ti1.addEventListener("focusOut", assignSpecialParam);
                
                /* Define the pass-through method in the addEventListener() method call.
                   You can add any number of parameters, as long as teh target method's 
                   signature agrees. */
                myButton.addEventListener(MouseEvent.CLICK, function (e:MouseEvent):void {
                        myClickListener(e, specialParam1, specialParam2);
                    }
                );          
            }
            
            private function assignSpecialParam(e:Event):void {
                specialParam1 = ti1.text;
            }
            
            /* This method acts as the event listener, and it has any 
             number of parameters that we defined in the addEventListener() call. */
            private function myClickListener(e:MouseEvent, s1:String, s2:String) : void {
                myButton.label = s1 + " " + s2;
            }           
        ]]>
    </fx:Script> 

    <s:Button id="myButton" label="Click Me"/>
    <s:TextInput id="ti1" text="Enter a custom String here." width="250"/>

</s:Application>

The executing SWF file for the previous example is shown below:

Another approach to passing additional parameters to the listener function is to define them in the listener function and then call the final method with those parameters. If you define an event listener inline (inside the MXML tag), you can add any number of parameters as long as the listener function’s signature agrees with that number of parameters.

The following example passes a string and the Event object to the runMove() method:

<?xml version="1.0"?>
<!-- events/MultipleHandlerParametersInline.mxml -->
<s:Application 
    xmlns:fx="http://ns.adobe.com/mxml/2009"    
    xmlns:mx="library://ns.adobe.com/flex/mx"     
    xmlns:s="library://ns.adobe.com/flex/spark">
    
    <s:layout> 
        <s:VerticalLayout/> 
    </s:layout>

    <fx:Script>
        <![CDATA[
        public function runMove(dir:String, e:Event):void {
            if (dir == "up") {
                moveableButton.y = moveableButton.y - 5;
            } else if (dir == "down") {
                moveableButton.y = moveableButton.y + 5;
            } else if (dir == "left") {
                moveableButton.x = moveableButton.x - 5;
            } else if (dir == "right") {
                moveableButton.x = moveableButton.x + 5;
            }
        }
        ]]>
    </fx:Script>

  <mx:Canvas height="100%" width="100%">
     <s:Button id="moveableButton" 
        label="{moveableButton.x.toString()},{moveableButton.y.toString()}" 
        x="75" 
        y="100" 
        width="80"
     />
  </mx:Canvas>

  <s:VGroup horizontalAlign="center">
     <s:Button id="b1" 
        label="Up" 
        click='runMove("up",event);' 
        width="75"/>
        <s:HGroup horizontalAlign="center">
           <mx:Button id="b2" 
            label="Left" 
            click='runMove("left",event);' 
            width="75"/>
           <s:Button id="b3" 
            label="Right" 
            click='runMove("right",event);' 
            width="75"/>
        </s:HGroup>
     <s:Button id="b4" 
        label="Down" 
        click='runMove("down",event);'
        width="75"/>
  </s:VGroup>

</s:Application>

The executing SWF file for the previous example is shown below: