Home > Best Practices, Flex, Learn This, Opinion, Random Notes, tutorial > An indepth look at Flex Events

An indepth look at Flex Events

March 2nd, 2009

One of the great things about I love about Flex is that it is fairly close to writing a desktop application. You can, for the most part, even take a Flex application and publish it as an AIR application for your desktop. In my opinion, one thing that makes it extremely similar is the way it handles Events. Its all about the eventListeners. As we all know, it is never as easy as adding an eventListener in one spot and a eventHandler in another. Within this article, I want to discuss how to add and handle eventListeners, dispatching them, how to stop event from propagating, difference between a target and a currenttarget, and the ever important thought of when to remove events.


Constructor of the Event class

Lets say you want to create an event. When you instantiate your Event object, it has three parameters: Type:String, Bubbles:Boolean, Cancelable:Boolean.

The type is going to be the name of the event. It is common practice to use constants for this (such as MouseEvent.CLICK), or you could just use “click” instead.

The Bubbles parameter is used to tell the event whether to bubble the event up to the parent class(es) or not. If your application has a button and you have a MouseEvent.CLICK listener in both your application and on your button, if you do not want that specific event to reach your applications eventlistener, you would set bubbles to false.

Cancelable is an interesting one. Some of the built in events have default behavior associated with them. One example is the MouseEvent.DOUBLE_CLICK event. When you fire this event, it will highlight the string that the mouse is hovering over. If you wanted to stop this, you would set cancelable to true. After you have set that, in your eventHandler, you would then do something like this:

public function clickHandlerFunction(event:MouseEvent):void{
    event.preventDefault();
}

However, if the event is not cancelable, then nothing will happen. You can check your event to see if it is cancelable by checking Event.cancelable property.

Basic adding and handling EventListeners
Adding an event is fairly straight forward.

public function creationComplete():void{
    addEventListener(MouseEvent.CLICK,clickHandlerFunction);
}

What this does is tells our component to “listen” for an event with the type MouseEvent.CLICK (which is a constant string). Upon reading that, it will be sent to the eventHandler, clickHandlerFunction, which looks something like this

public function clickHandlerFunction(event:MouseEvent):void{
    trace("Click Event handled");
}

Once the handler is reached, it will just output “Click Event Handled”.

Lets say you don’t want to add an eventListener to the main component or application and you want to add it to the component specifically, such as a button. This would make it so your event chain will go to the button that was listening first. If we added this to our creationComplete handler:

public function creationComplete():void{
    addEventListener(MouseEvent.CLICK,clickHandlerFunction);
    button.addEventListener(MouseEvent.CLICK,buttonClickHandlerFunction);
}
public function buttonClickHandlerFunction(event:MouseEvent):void{
    trace("Button Click Event handled");
}

Upon clicking the button, we would get an output like this:

Button Click Event Handled
Click Event Handled


Manually dispatching events

There are plenty of times where we cant just hook all of our event dispatching through something like clicking a button. We may run into situations that depending on the state of our application, we might want to dispatch a different event. In this case, we would need to manually dispatch the event. In order to do this, we would call dispatchEvent, which would look like this:

public function buttonClickHandlerFunction(event:MouseEvent):void{
    if (applicationState == "dirty")
        dispatchEvent(new Event(EventType.GETDATA,true,false));
    else
        dispatchEvent(new Event(EventType.REFRESH,true,false));
}

In this scenario, we have an eventHandler that verifies the state of our application. If our applicationState is dirty, we fire off a GETDATA event. If not, we then fire off a REFRESH event. Each one off these events would have an eventHandler listening for these functions and will handle them however we wish.

But what if your component or object does not have access to the dispatchEvent function. Most components WILL have it, but not every one of them will. In order to gain access to it, we have a few options. The easiest way to handle it is to just include an IEventDispatcher object and dispatch our events through that.

public class ExampleDispatcher{
    var dispatcher:IEventDispatcher;
    public function ExampleDispatcher(){
      dispatcher = new EventDispatcher();
    }
    public function dispatchEvent():void{
      dispatcher.dispatchEvent(new Event(MouseEvent.CLICK,true,false));
    }
  }

A few other ways to handle it is you could extend the EventDispatcher if you are able too. If you are not able to (IE: you are already extending another class), you could implement IEventDispatcher and handle the functions yourself. Personally, I find it easier to just use a IEventDispatcher object. What is nice about this is you can assign your IEventDispatcher object to anything. It could be the standard EventDispatcher or it could be CairngormEventDispatcher if you wanted.

Halting events
Say we have an event bubble chain in our program. An event gets fired and it just goes all the way up through our nodes all the way to the top (main application). We end up having something like C bubbles to B and B bubbles to A. What if we have a bad state by the time our event bubbles to B and we want prevent the event flow from reaching A?

We have two functions on our Event object that we can use in order to do this, stopPropagation and stopImmediatePropagation. Both of these methods will stop the Event from reaching its next node (aka currentTarget). The difference between stopPropagation and stopImmediatePropagation is that stopImmediatePropagation will not only prevent the event from moving to the next node, but it will also prevent any other listeners on that node from capturing their events.

Here is a good example to show the difference between the two:

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
   layout="absolute" initialize="init(event)">
    <mx:Script><![CDATA[
        import mx.controls.Alert;
        import flash.events.MouseEvent;
 
        public function init(e:Event):void {            
            button.addEventListener(MouseEvent.CLICK,showAlert);
            panel.addEventListener(MouseEvent.CLICK,showAlert);
            panel.addEventListener(MouseEvent.CLICK,stopImmediatePropagationExample);
            vbox.addEventListener(MouseEvent.CLICK,showAlert);
        }
        public function stopImmediatePropagationExample(e:Event):void {
            Alert.show("stopImmediatePropagationExample!\n" + e.currentTarget);
        }
        public function showAlert(e:Event):void {
            Alert.show("Alert!\n" + e.currentTarget);
            //e.stopImmediatePropagation();
            e.stopPropagation();
        }
 
    ]]></mx:Script>
 
    <mx:Panel id="panel" title="Click me ">
        <mx:VBox id="vbox" width="200" height="100" >
            <mx:Button id="button" label="Click Me Too"/>
        </mx:VBox>
    </mx:Panel>
 
</mx:Application>

In this example, I have setup the panel to have two eventListeners and the other components to have one. If you have stopImmediatePropagation uncommented in the showAlert function and you click the panel, it will only show the alert once. If you have stopPropagation uncommented, it will show it twice. This is because

  1. it is on the same currentTarget and we have not switched nodes
  2. stopPropagation does not stop the other listeners on that node. It is stopImmediatePropagation that handles that part.

If you have stopImmediatePropagation or stopPropagation uncommented and click anywhere else, it will show the alert once. This is because both of them prevent you from moving to the next node.

Difference between a target and a currenttarget
The last section was not only a good example on how to halt events, but it was also a good example of how bubbles works. If you remove both stopImmediatePropagation and stopPropagation, you will see the event chain as it bubbles up to the top. You will notice in the showAlert function, we were displaying the currentTarget. This is the node that currently on within the bubbling phase.

The Event object will have both a target property and a currentTarget property. The difference between the two are that currentTarget is the node that we are currently on within the bubble phase. The target property is used to show who initiated the event. However, do not be deceived by this. To take an exert from the Flex docs:

When you handle a mouse event such as MouseEvent.CLICK by writing a listener on some component, the event.target property does not necessarily refer to that component; it is often a subcomponent, such as the Button control’s UITextField, that defines the label.

I find myself using currentTarget more often than not to find out where the event came from, as long as I’m not using bubbling.

When to remove eventListeners

In one my previous articles, I spoke about overriding some core functions that UIComponent implements. Two that come to mind in this example are commitProperties and updateDisplayList. Along with me voicing my concern with people wanting to add children in there, they also need to be careful about adding eventListeners in there. If we do that, we may end up constantly adding eventListeners on top of each other, one after another after another after another. *IF* you decide to do that, make sure you call removeEventListener first, just to be safe. The main problem you run into though when you let rogue eventListeners live forever is that they are still holding a reference to that object, making garbage collection a pain.

On the outside, Flex events seem quite simple. Something listens for them and something else dispatches them. As you can see, it is not that simple. Events serve as the communications line within your application. Making sure you are as knowledgeable as possible on them is extremely important. If you feel there is something about events that I left out that is equally as important, feel free to comment.

Best Practices, Flex, Learn This, Opinion, Random Notes, tutorial , , ,

  1. burritobob
    March 2nd, 2009 at 05:42 | #1

    good writeup. Concerning the removing of listeners. Lets say for example I have a set up a listener onRegister, for when a button gets clicked. So in the function that handles the event, I should remove the listener ? Where do I re register to associate the listener with the button , in the same function ?. thanks

  2. March 2nd, 2009 at 09:52 | #2

    bob,

    When it comes to removing events, really the main thing you have to be concerned with is when you are no longer going to use that object. If it is just a button that you are going to be using throughout the lifetime of the application and you are only creating that button once, then no worries. You can leave it there. The example I used was when people make the mistake of adding them within something like commitProperties, which gets called multiple times on the same object. Another example is within item renderers. If you are going to set your object up where event listeners are added multiple times, please be aware that they may add up :) .

    Hope that helps!

  3. March 2nd, 2009 at 09:56 | #3

    You forgot my favorite / most used event argument – useWeakReferences! Events default to using Strong references to listeners, which means that you can have situations in which you lose your named reference to the host of a listener, thus preventing you from removing the event listener. The listener floats around in memory, never to be garbage collected, because of the strong reference. Setting useWeakReferences to true avoids this potential problem. There are a couple of situations where you’d want to be careful with weak references, though – most notably in the case of using an anonymous function as your listener, since a weak reference would garbage collect the function before it is called!

    David Coletta has some good points here: http://www.colettas.org/?p=115

  4. Darren
    March 2nd, 2009 at 17:46 | #4

    This bit doesn’t make a lot of sense to me, “One example is the MouseEvent.DOUBLE_CLICK event. When you fire this event, it will highlight the string that the mouse is hovering over.” Highlight the string? I guess you mean the label or the UITextField of a standard Button? It doesn’t seem to make any changes to this for me either. It just briefly shows the downSkin which effectively changes the background colour of the button.

    @ Justin, I find it easiest to create a custom event with weakReferences set to true and extend this for all my other events. Easier than writing out all those extra parameters every time just to set the fifth one to true when you usually only need the first two. You can add a generic data Object to this event too to make it more useful, or just extend DynamicEvent for your custom event.

  5. March 3rd, 2009 at 02:29 | #5

    It’s interesting you say that the flash event model makes it similar to developing desktop applications… To me it makes it more similar to developing web applications – it’s basically the W3C event model which has been available in web browsers through javascript for years…

  6. March 3rd, 2009 at 10:00 | #6

    Darren,

    Yeah, I could have been a bit clearer about the preventDefault. Here is a good example of what I was referring to:
    Check this out
    Each type they type out something, it goes to the textEvent. If the text is a “\n”, it will prevent the default action, when is to display it within the input box.

    Hope that helps!

  7. March 3rd, 2009 at 10:04 | #7

    Kevlin,

    I could agree with you, its definitely good for web applications. Although javascript didnt come to mind first since I do have limited exposure to it. I was thinking about it being like developing a desktop application since since they run in their own little VM and just the way events are handled remind me a lot of java action listeners. Certainly a lot of less form submits than normal web applications :P .

  8. July 29th, 2009 at 06:53 | #8

    Hi… many thanks for the great post… I actually have a problem with my combobox which is customized to select multiple items. The problem is, it fires multiple change events on selection change; so is there any way to stop an event already fired?
    The detail is posted here: http://forums.adobe.com/thread/469331
    Regards,
    Siraj

  9. rahul agarwal
    June 10th, 2010 at 02:28 | #9

    stop propagation and stopImmediatePropagation is good but bubble and cancalable is not properly present

  10. August 14th, 2010 at 18:24 | #10

    Specialists tell that business loans help a lot of people to live the way they want, because they can feel free to buy needed stuff. Moreover, a lot of banks present college loan for young and old people.

  11. Anonymous
    December 15th, 2010 at 23:04 | #11

    i want clear explanation about stop propagation and stopimmediatepropagation

  1. March 2nd, 2009 at 11:10 | #1