Understanding Event Flow and Event Bubbling


It might be helpful to understand how Flash Player handles events. Whenever an event occurs, Flash Player dispatches an event. If the event target is not a visible element on the screen, Flash Player can dispatch the event object directly to the designated target. For example, Flash Player dispatches the result event directly to an HTTPService component. However, if the target is a visible element on the screen, Flash Player dispatches the event and it travels from the outermost container (the Application container), down through the target component, and then back up to the Application container.

Event flow is a description of how that event object travels through an application. As you have seen by now, Flex applications are structured in a parent-child hierarchy, with the Application container being the top-level parent. Earlier in this lesson, you saw that flash.events.EventDispatcher is the superclass for all components in Flex. This means that every object in Flex can use events and participate in the event flow; they can all listen for an event with the addEventListener() method, but will hear the event only if the listening object is part of the event flow.

When an event occurs, an event object makes a round trip from the root application, through each of the containers on the way to the component that was responsible for the event (known as the target of the event). For example, if a user clicks a Button named button, Flash Player will dispatch an event object whose target is button. Although the target of an event is constant throughout the flow, an event object also has a currentTarget property, which indicates which element in the flow currently has the event object.

The event flow is conceptually divided into three parts:

  • The capture phase comprises all the containers from the base application to the one containing the event's target.

  • The target phase consists solely of the target node.

  • The bubbling phase comprises all the elements encountered on the return trip from the target back to the root application.

The following image describes a branch of an application, in which a Button is contained within an HBox, which is contained by a Panel, which sits in the root Application. For the context of this example, other elements in the application are moot.

If a user clicks the Button, Flash Player dispatches an event object into the event flow. The object's journey starts at the Application, moves down to the Panel, moves to the HBox and finally gets to the Button. The event object then "bubbles" back up to Application, moving again through the HBox and Panel on its way up.

In this example, the capture phase includes the Application, Panel and HBox during the initial downward journey. The target phase comprises the time spent at the Button. The bubbling phase comprises the HBox, Panel, and then Application containers as they are encountered during the return trip.

This event flow offers far more power and flexibility to programmers than the event model of previous versions of ActionScript. Prior to Flex 2, event listeners had to be assigned directly to the object that generated an event. In Flex 2, you can still do this or you can register event listeners on any node along the event flow.

All instances of the Event class have a bubbles property that indicates whether that event object will participate in the bubbling phase of the event flow. You can look to the API documentation to find out whether a particular event type will bubble.

In practicality, this means that an event can occur in a child component and be heard in a parent. Consider this simple example:

<?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"    click="showAlert(event)" >    <mx:Script>       import mx.controls.Alert;       private function showAlert(event:Event){          var msg:String = event.target.toString() +" clicked";          Alert.show(msg);       }    </mx:Script>    <mx:Panel        click="showAlert(event)" >       <mx:HBox           click="showAlert(event)" >          <mx:Button              click="showAlert(event)"/>       </mx:HBox>    </mx:Panel> </mx:Application> 


In this case, there is a Button control inside an HBox, inside a Panel, inside an Application. When the button is clicked, the click event of the Button control is heard from the event handler of the Button, HBox control, Panel, and Application, and as such, four Alert boxes pop up, all saying the following:

Application4.panel:Panel.hbox:HBox.button:Button clicked 


The click event of the Button control can be captured at the Button control itself or in any of the parent containers of the Button instance. This happens because click is a bubbling event. The bubbles property of the Event class is Boolean, which indicates whether an event should bubble. By default, bubbles is set to false on newly created events (although it is preset to TRue for some built-in events, such as click). When you create event instances or event subclass instances, you can decide whether you want to enable bubbling for the event. If you leave the bubbling to the default false value, the event can be captured only at the source of the event (the Button control in the preceding example). However, if it is set to true, it can be captured by a parent of the dispatching component (such as the HBox, Panel and Application).

In the EComm application, when the itemAdded event is dispatched from the GroceryDetail component, currently you are capturing the event in FoodList and then redispatching it.

However, if the ProductEvent could optionally be set to bubble, there would be no need for the FoodList to capture and rebroadcast the eventit could be handled directly in the EComm application.

1.

Open ProductEvent.as from your flexGrocer/events directory.

Alternatively, you can open ProductEvent_initial.as from Lesson09/intermediate and save it in your flexGrocer/events directory as ProductEvent.as.

2.

Add a third argument to the constructor: bubbles of data type Boolean with a default value of false.

public function ProductEvent(prod:Product, type:String, bubbles:Boolean=false){ 


Throughout this lesson, you have been creating instances of the ProductEvent class, which did not bubble. So you don't need to go back to all of them and specifically specify false as the third argument to the constructor. A default value of false is used. Therefore, when only two values are passed, the bubbles argument comes through as false.

3.

Inside the constructor, pass the bubbles argument to the constructor of the superclass. You should also pass the bubbles parameter in the call to create a new ProductEvent in the clone() method.

package events{    import flash.events.Event;    import valueObjects.Product;    public class ProductEvent extends Event{       public var product:Product;       public function ProductEvent(prod:Product, type:String, bubbles:Boolean=false){          super(type, bubbles);          product = prod;       }       public override function clone():Event{          return new ProductEvent(product, type, bubbles);       }    } } 


The flash.events.Event class takes an optional second argument to its constructor that indicates whether the event should bubble. If not provided, the default value of false is used.

Save and close ProductEvent.as. It is now ready to creating bubbling instances when requested.

4.

Open GroceryDetail.mxml from flexGrocer/views/ecomm.

Alternatively, you can open GroceryDetail_event from Lesson09/intermediate and save it as GroceryDetail.mxml in your flexGrocer/views/ecomm directory.

5.

Inside the itemAdded() method, add true as the third argument when creating the ProductEvent instance.

private function itemAdded(prod:Product):void{    var e:ProductEvent = new ProductEvent(prod,"itemAdded",true);    dispatchEvent(e); } 


This one instance of the ProductEvent class is told to bubble. Now you no longer need to capture the event in FoodList; you can instead capture it directly in EComm.

Save and close GroceryDetail.mxml.

6.

Open FoodList.mxml from views/ecomm.

Alternatively, you can open FoodList_event from Lesson09/intermediate and save it as FoodList.mxml in your views/ecomm directory.

7.

Remove the itemAdded event handler from the instantiation of the GroceryList component. Also delete the addItem method from this file.

The remaining code in FoodList.mxml should look like this:

<?xml version="1.0" encoding="utf-8"?> <mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml"    xmlns:v="views.ecomm.*">    <mx:Metadata>       [Event(name="itemAdded",type="events.ProductEvent")]    </mx:Metadata>    <mx:Script>       <![CDATA[          import mx.collections.ArrayCollection;          import events.ProductEvent;          [Bindable]          public var prodByCategory:ArrayCollection;       ]]>    </mx:Script>    <mx:Repeater        width="100%" height="100%"       dataProvider="{prodByCategory}">       <v:GroceryDetail           width="80%"          groceryItem="{foodRepeater.currentItem}"/>    </mx:Repeater> </mx:VBox> 


You no longer need to capture and redispatch the itemAdded event here. You do, however, need to have the Event metadata for itemAdded, so the compiler will enable EComm to listen to this component for the event.

Save and close FoodList.mxml. Run EComm.mxml and notice that items are still properly added to the cart.




Adobe Flex 2.Training from the Source
Adobe Flex 2: Training from the Source
ISBN: 032142316X
EAN: 2147483647
Year: 2006
Pages: 225

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net