Welcome!

Adobe Flex Authors: Liz McMillan, RealWire News Distribution, Maureen O'Gara, Yakov Fain, Keith Swenson

Related Topics: Adobe Flex

Adobe Flex: Article

Flex Is All About Event-Driven Development

Flex Best Practices: An Application with a Single Event Class

An Application with a Single Event Class
Flex is all about event-driven development. Create loosely coupled objects and let them send events to each other. You can read about this in the following blog.

In a nutshell, you can create new events for every occasion. If an event doesn't need to carry any additional data, just extend flash.events.Event and define the meta-tag to help Flex Builder list this event in its type-ahead prompts and dispatch it when appropriate. If your new event needs to carry some data, create an ActionScript class, define a variable in your subclass to store your data, and override the method clone().

If we take a mid-size Website with 10 views, where each view has two components that can send/receive two events, you can quickly reach 40 or more custom Event-based classes that look pretty much the same. To ensure that the situation does not get out of control, some of the Flex frameworks force you to register each event upfront in a central location.

We say, “No need to do it. You can get away with one event.” The sample application below has only one defined event class that can fit multiple purposes without the need to introduce tight coupling between your application components.
To illustrate the concept, I’ve created a simple application that looks as follows:


 
This application consists of two modules (GreenModule and RedModule) that are loaded in the same area of the main application with the click of the appropriate Load button. It also has one universal event class called ExEvent. If you click on the Send buttons, an instance of this event is created and there you can put an instance of Object, a DTO, a couple of string variables, nothing, or anything else you like. In this example I’m using a DTO class called GirlfriedDTO.as. There is no mapping between the event you send and the modules. For example, if you send a Green event to the Red module, nothing happens since the Red module is not listening to the Green event.

I’ve been using modules in this application, not because I endorse them, but because they give me a chance to quickly illustrate a concept of run-time loading and loose coupling between the objects and events. Victor Rasputnis, my colleague at Farata Systems, has been experimenting with modules and next month will publish an article that describes his findings.

A completed application and its source code is deployed at this URL. Its Flex Builder’s project has a folder module that contains two modules: red and green. The red one is listening for the arrival of the girlfriend’s first and last name, packaged in our single event class as two separate strings:

<?xml version="1.0" encoding="utf-8"?>
<mx:Module xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"  
    width="100%" height="100%" creationComplete="onCreationComplete(event)">
    <mx:TextArea id="display" backgroundColor="#FF4949"  width="100%" height="100%"  fontSize="28"/>
        <mx:Script>
        <![CDATA[
    private function onCreationComplete(evt:Event):void{
        this.addEventListener("RedGirlfriend", onRedGirlfriend);
            }
            
    private function onRedGirlfriend(evt:ExEvent):void{
            
        display.text="My girlfriend is "+ evt.fName+ " " + evt.lName ;
            }
        ]]>
    </mx:Script>
</mx:Module>

The green module expects the girlfriend’s name in a form of GirlfriendDTO:

<?xml version="1.0" encoding="utf-8"?>
<mx:Module xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" width="100%" height="100%"
    creationComplete="onCreationComplete(event)">
    <mx:TextArea id="display" backgroundColor="#9CE29C" width="100%" height="100%" color="#070707" fontSize="28"/>
    <mx:Script>
        <![CDATA[
        import dto.GirlfriendDTO;
            
        private function onCreationComplete(evt:Event):void{
        this.addEventListener("GreenGirlfriend", onGreenGirlfriend);
            }
            
        private function onGreenGirlfriend(evt:ExEvent):void{
         var myGirlfriend:GirlfriendDTO=evt["girlfriend"];
                
          display.text="My girlfriend is "+ myGirlfriend.fName+ " " +
                                                      myGirlfriend.lName ;
         }
        ]]>
    </mx:Script>
</mx:Module>

The GirlfriendDTO is located in the folder dto and is pretty straightforward too:

package dto
/**
 * This is a sample data transfer object (a.k.a. value object)  
 */
{
    public class GirlfriendDTO
    {
         public var fName:String; // First name
         public var lName:String; // Last name  
    }
}

Now let’s talk about our single but universal event class. It’s based on the DynamicEvent class, which allows you to add any properties to the event object on the fly.  Surprisingly, Flex documentation discourages you from using this class. Here’s what it states:

This subclass of Event is dynamic, meaning that you can set arbitrary event properties on its instances at runtime. By contrast, Event and its other subclasses are non-dynamic, meaning that you can only set properties that are declared in those classes. When prototyping an application, using a DynamicEvent can be easier because you don't have to write an Event subclass to declare the properties in advance. However, you should eventually eliminate your DynamicEvents and write Event subclasses because these are faster and safer. A DynamicEvent is so flexible that the compiler can't help you catch your error when you set the wrong property or assign it a value of an incorrect type.

Let me respectfully disagree with this recommendation and suggest you use the dynamic nature of this event, not only for prototyping, but also for development and deployment of your applications. When GUI components send event sto each other, the difference in the processing of your dynamic versus static event instance is negligible. It’s not clear how much safer the static event is. I don't think so.

When you design an event-based interaction between components of your applications, both the sending and receiving parties must know in which format the data is being delivered by an event. And we utilize  this knowledge even in case of the dynamic events. We can use either a well-defined GirlfriendDTO:
  
            var myDTO:GirlfriendDTO=new GirlfriendDTO();            
            myDTO.fName="Mary";
            myDTO.lName="Poppins";
            
            var greenEvent:ExEvent=new ExEvent("GreenGirlfriend");
            greenEvent.girlfriend=myDTO;
                
            someObject.dispatchEvent(greenEvent);

or just add two string variables:

            var redEvent:ExEvent=new ExEvent("RedGirlfriend");
                
            redEvent.fName="Mary";
            redEvent.lName="Poppins";
            someObject.dispatchEvent(redEvent);

In this sample I use an ExEvent, which is a subclass of the DynamicEvent – it has just a minor enhancement that eliminates manual programming of the property Event.preventDefault:

package
{
    import mx.events.DynamicEvent;
    public dynamic class ExEvent extends DynamicEvent
    {
        private var m_preventDefault:Boolean;

        public function ExEvent(type:String, bubbles:Boolean = false,
                                         cancelable:Boolean = false)     {
            super(type, bubbles, cancelable);
            m_preventDefault = false;
        }

        // It's an enhancement: DynamicEvent class does not
        // automatically process preventDefault in cloned events
        public override function preventDefault():void         {
            super.preventDefault();
            m_preventDefault = true;
        }

        public override function isDefaultPrevented():Boolean     {
            return m_preventDefault;
        }
    }
}

Now the code of the test application loads modules, and then the user can send any event to whichever module is loaded at the moment. Of course, if the currently loaded module does not have a listener for the event you’re sending, tough luck. Do not expect miracles – nothing will happen. But the good news is that it won’t break the application either:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" viewSourceURL="srcview/index.html">
 <mx:HBox>
    <mx:Button label="Load the Green Module" click="loadMyModule('modules/GreenModule.swf')"/>
    <mx:Button label="Load the Red module" click="loadMyModule('modules/RedModule.swf')"/>
    <mx:Button label="Send Green Event with Object" click="sendGreen()"/>
    <mx:Button label="Send Red Event Event with two strings" click="sendRed()"/>
         
 </mx:HBox>
 
<mx:Panel width="100%" height="100%" title="A module placeholder" layout="absolute">
<mx:ModuleLoader id="theModulePlaceholder" width="100%" height="100%"/>
</mx:Panel>
<mx:Script>
    <![CDATA[
        import dto.GirlfriendDTO;
        //Load the module specified in the moduleURL
        private function loadMyModule(moduleURL:String):void{
            theModulePlaceholder.url=moduleURL;
            theModulePlaceholder.loadModule();
        }
        
        // Sending generic  ExEvent adding an object that contains
        // the name of the girlfriend
        private function sendGreen():void{
            
            // Strongly typed DTO - better performance and readability,
            // but its structure has to be known for both parties -
            // the main application and the module
            var myDTO:GirlfriendDTO=new GirlfriendDTO();            
            myDTO.fName="Mary";
            myDTO.lName="Poppins";
            
            if (theModulePlaceholder.child !=null){
                var greenEvent:ExEvent=new  
                                          ExEvent("GreenGirlfriend");
                greenEvent.girlfriend=myDTO;
                
                theModulePlaceholder.child.dispatchEvent(greenEvent);
            }
        }
        
    // Sending a generic ExEvent that holds the name of the girlfriend
    // as two separate variables
        private function sendRed():void{
                var redEvent:ExEvent=new ExEvent("RedGirlfriend");
                
                redEvent.fName="Angelina";
                redEvent.lName="YouKnowWho";
                
                if (theModulePlaceholder.child !=null){
                theModulePlaceholder.child.dispatchEvent(redEvent);
                }
        }            
    ]]>
</mx:Script>
</mx:Application>

The function sendGreen() sends an instance of our ExEvent event with DTO, while the sendRed() just adds two properties, fName and lName, to the instance of the ExEvent.

Instead of using a well-defined DTO, I could’ve used a weakly typed data transfer object:

            var myDTO:Object={fname:"Mary",lname:"Poppins"};

But this would result in poor readability of the code and a bit slower performance. On the positive side, there would be no need to explicitly define and share the class structure of the dto  between the app and the module. I’d do something like this during the prototyping stage, but not in real code.

Let’s recap. What did we gain? No need to create lots of tedious coding, defining dozens of similar event classes. What did we lose? Since we did not use the metatag Event declaring the names of the events, those never declared event classes, Flex Builder won’t be able to help us with the name of the event in its type-ahead help. No biggie.

In the unlikely case if there is a view in your application that can’t afford to lose a couple of milliseconds caused by using a dynamic event, use static but in that view only. But with a single dynamic event, the code base of your project will become smaller and more readable.

More Stories By Yakov Fain

Yakov Fain is a Managing Director of Farata Systems, consulting, training and product company. He has authored several Java books, dozens of technical articles. SYS-CON Books released his latest co-authored book , Rich Internet Applications with Adobe Flex and Java: Secrets of the Masters in Spring 2007. Sun Microsystems has nominated and awarded Yakov with the title Java Champion. He leads the Princeton Java Users Group. He is an Adobe Certified Flex Instructor. Currently Yakov works on the book for O'Reilly "Enterprise Application Development with Flex". He twits at twitter.com/yfain.

Comments (0)

Share your thoughts on this story.

Add your comment
You must be signed in to add a comment. Sign-in | Register

In accordance with our Comment Policy, we encourage comments that are on topic, relevant and to-the-point. We will remove comments that include profanity, personal attacks, racial slurs, threats of violence, or other inappropriate material that violates our Terms and Conditions, and will block users who make repeated violations. We ask all readers to expect diversity of opinion and to treat one another with dignity and respect.