Adobe Flex 3 Help

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 -->
    <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
        <mx:Script><![CDATA[
            import mx.controls.Alert;
    
            private function myEventHandler(event:Event):void {
                Alert.show("An event occurred.");
            }
        ]]></mx:Script>
    
        <mx:Button id="b1" label="Click Me" click="myEventHandler(event)"/>
    
    </mx:Application>
    
    

    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 -->
    <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="initApp();">
        <mx: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.");
            }
        ]]></mx:Script>
    
        <mx:Button id="b1" label="Click Me"/>
    
    </mx:Application>
    
    

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

<mx:tag_name event_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:

<mx:Script><![CDATA[
    function submitForm():void {
        // Do something.
    }
]]></mx:Script>
<mx: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:

<mx: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 -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
    <mx: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.");     
        }
    ]]></mx:Script>

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

</mx: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 -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
    <mx:Script><![CDATA[
        import mx.controls.Alert;
    
        private function myEventHandler(s:String):void {
            Alert.show("Current Target: " + s);
        }
    ]]></mx:Script>

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

</mx: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 -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" initialize="createListener()">
  <mx: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.");
     }
  ]]></mx:Script>
  <mx:Button label="Click Me" id="b1"/>
</mx: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 -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
  <mx:Script><![CDATA[
  import mx.controls.Alert;

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

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

</mx: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 -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="initApp()">
    <mx:Script><![CDATA[    
    import mx.controls.Alert;

    private function initApp():void {
        b1.addEventListener("click", 
            function(e:Event):void {
                Alert.show("The button was clicked.");        
            }
        );        
    }
    ]]></mx:Script>
    <mx:Button id='b1' label="Click Me"/>
</mx: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 -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="foo()">
    <mx: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
    }
    
    ]]></mx: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>

    <mx:Button id='b1' label="Compute Product" click="bar()"/>
</mx: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 cleared from memory. 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 -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" initialize="createHandler(event)">
  <mx: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.");
     }
  ]]></mx:Script>

  <mx:Button id="b1" label="Click Me"/>
  <mx:Button label="Click Me Too" id="b2" click="myClickHandler(event)"/>
  <mx:Button label="Remove Event Listeners" id="b3" click="removeMyHandlers(event)"/>
</mx: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 -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" initialize="createHandler()">
  <mx:Script><![CDATA[
     private var myListener:MyEventHandler = new MyEventHandler();

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

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

</mx: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 -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" initialize="createHandler()">
  <mx:Script><![CDATA[
     private function createHandler():void {
        b1.addEventListener(MouseEvent.CLICK, MyStaticEventHandler.handleAllEvents);
  }
  ]]></mx:Script>

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

</mx: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.