Flex Events and FlashBuilder Event Meta Tags

As so many of these things go I’m sure this information is out there somewhere… I’ve even probably read it.   For whatever reason it didn’t “click” for me.   I figured out how to effectively leverage the Flex Event meta tags in FlexBuilder.

Now I’m not going to get into why you should use an event architecture… there are lots of articles on that and I’m sure by this time most developers are using events.  I will lay out my preference on how to set up events.

So if you are not familiar with it there is this neat little meta tag for attaching events to the a dispatcher.  The tag looks something like this:


[Event(name="someEventName",type="com.some.thing.fooEvent")]

Now as meta tags go this one is NOT required by the compiler (as opposed to say [Bindable] ) so it is completely optional. However if you are using FlashBuilder let me tell you what magic happens when you do use it correctly.

First let me talk a bit about how I like to create events.   I’ve become quite fond of creating individual event classes for each event type of event I want to dispatch.  Confused?  Well there are two approaches to creating custom event classes that I’ve seen floating about.  The first creates a custom event class that has a number of constant values that can be passed into the constructor for the event type.  It looks something like this:

package com.some.thing.foo {
	import flash.events.Event;
	public class FooEvent extends Event	{
		public static const OPEN_FOO_EVENT:String = "openFooEvent";
		public static const CLOSE_FOO_EVENT:String = "closeFooEvent";
		public function FooEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=false)
		{
			super(type, bubbles, cancelable);
		}
	}
}

Now to create an event of this type you call  it something like this.  (from inside of your class that extends event dispatcher):

import com.some.thing.foo.FooEvent
dispatchEvent(new FooEvent(FooEvent.OPEN_FOO_EVENT));

Now there is nothing really wrong with this…. except it doesn’t do much for you and here is why.

First imagine that you have 50 different events you want to dispatch that do not include any additional data other than the fact that the event was dispatched.  Ok so you create an event class like the above FooEvent class, add 50 different constants and there you go.   Great, but what a waste.  You could have done basically the same thing by simply putting the constants in your dispatcher class and creating a generic event.  Ala…

import flash.events.Event;
public static const OPEN_FOO_EVENT:String = "openFooEvent";
public static const CLOSE_FOO_EVENT:String = "closeFooEvent";
dispatchEvent(new Event(OPEN_FOO_EVENT));

Didn’t really do much except for add a new class that does nothing.  Either way you have to pass the constant in to the event to make sure it gets the right type.

Now imagine the other scenario.  This is the situation where you want to include some data along with the event.  Your event might look like this.

package com.some.thing.foo {
       import flash.events.Event;
       public class BarEvent extends Event
       {
          public static const OPEN_BAR_EVENT:String = "openBarEvent";
          public static const CLOSE_BAR_EVENT:String = "closeBarEvent";
          public var phooy:String = "";
          public function BarEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=false)
          {
              super(type, bubbles, cancelable);
          }
       }
}

or this

package com.some.thing.foo {
       import flash.events.Event;
       public class Bar2Event extends Event
       {
          public static const OPEN_BAR_EVENT:String = "openBarEvent";
          public static const CLOSE_BAR_EVENT:String = "closeBarEvent";
          private var _phooy:String = "";
          public function Bar2Event(phooy:String, type:String, bubbles:Boolean=false, cancelable:Boolean=false)
          {
             this._phooy = phooy;
             super(type, bubbles, cancelable);
           }
           public function get phooy():String{
               return this._phooy;
           }
       }
}

Now you would dispatch these like this:

import com.some.thing.foo.BarEvent
import com.some.thing.foo.Bar2Event

   //For BarEvent
   var b:BarEvent = new BarEvent(BarEvent.OPEN_BAR_EVENT);
   b.phooy = "iphoney";
   dispatchEvent(b);

   //or for Bar2Event
   dispatchEvent(new Bar2Event("iphone home",Bar2Event.CLOSE_FOO_EVENT));

The question you have to ask yourself is;  Does either of these really help things, or do these methods make your code harder to read?

There is a better way…..Create individual event classes for each of your events.

Now before I go down that path I will say there is one benefit of doing things like the foo class above.  You have the ability to use the is operator to check for a common class type.  Which can come in handy somewhere in your code.  You might want your event handler to handle both foo open event and file open event and branch execution by type.  Ok so  to keep that ability (and just to make things clean) I’ll do the same thing.  The way I like to handle this is by creating a directory  and package structure like this.

com.some.thing.foo

com.some.thing.foo.FooBarDispatcher.as

com.some.thing.foo.events

com.some.thing.foo.events.FooEvent.as (extends flash.events.Event)

com.some.thing.foo.events.FooOpenEvent.as     (extends  FooEvent)

com.some.thing.foo.events.FooCloseEvent.as (extends FooEvent)

Now since we don’t have abstract classes in AS you just have to restrain yourself from directly creating the FooEvent or implement some sort of abstract enforcer at runtime.  For this I don’t bother since I might at some point want to directly dispatch a FooEvent.  (seems unlikely but who knows)

So now all my events will be FooEvents by inheritance.    If  I want to throw errors  I will also create a FooErrorEvent class  (extending flash.events.ErrorEvent )  and use that as the parent class for error events.

The FooEvent class here looks almost exactly like the first foo event class in this post except there are no constants in it.    Instead we define one and only one constant in each sub-class.

package com.some.thing.foo.events
{
    public class FooOpenEvent extends FooEvent
        {
         public static const FOO_OPEN_EVENT:String = "fooOpenEvnet";
         public function FooOpenEvent()
         {
             super(FOO_OPEN_EVENT);
         }
    }
}

Dispatched like this:

import com.some.thing.foo.events.*
dispatchEvent(new FooOpenEvent());

There are a couple of ways this makes the code cleaner.  First in the event class itself, no import statement is needed since the parent class is in the same package.  A small difference but small differences add up.

The next point of clarity  is that the line needed to dispatch the event is very clear.  All I need to know is right in front of me.  I don’t need to know where to get the constant.  I don’t need to know what constants are permissible.  I just create and dispatch the event.

Also in the event class you will notice that the event type that is passed to the parent class constructor’s type argument is fixed.  The type of this event will ALLWAYS be “fooOpenEvent”   This makes the code else where easy to read.  When you  have a listener that is getting an event of type  ”FooOpenEvent”, it is always a “fooOpenEvent”.    The the first example, a FooEvent could be either a “fooOpenEvent” or a “fooCloseEvent”.   This distinction isn’t so important for the compiler, internally it looks at the type string to determine event type, however for you in reading your code  think about this….

public function handleFooOpen(e:FooEvent){
   //Am I handleing the right event?...   e.Type?
   //the compiler won't throw an error if I'm wrong.
}
public function handleFooClose(e:FooEvent){
   //Am I handleing the right event?... e.Type?
   //the compiler won't throw an error if I'm wrong.
}
//versus the clarity of
public function handleFooOpen(e:FooOpenEvent){
   //I'm sure I have the right event or it won't compile.
}
public function handleFooClose(e:FooCloseEvent){
   //I'm sure I have the right event or it won't compile.
}

So think a bit about the above code.   The first two handlers would be what you would use with the first foo event class listed at the beginning of this post.   Notice how since they both take the same type (FooEvent) that if you were to accidently set up your addEventListener incorrectly you wouldn’t know it.  For example, considering the first two event handlers above.

//This is what you want....
fooBarInstance.addEventListener(FooEvent.OPEN_FOO_EVENT,handleFooOpen);
fooBarInstance.addEventListener(FooEvent.CLOSE_FOO_EVENT,handleFooClose);
//But this would be valid too... the compiler would be just happy
fooBarInstance.addEventListener(FooEvent.OPEN_FOO_EVENT,handleFooClose);
fooBarInstance.addEventListener(FooEvent.CLOSE_FOO_EVENT,handleFooOpen);

In contrast, the last two handlers use different types, so if you try to attach them as event listeners to the incorrect type of event, the pre-compiler in FlashBuilder will report a problem.  For example… (considered with the last two event handlers from above)

//This would work....
fooBarInstance.addEventListener(FooOpenEvent.FOO_OPEN_EVENT,handleFooOpen);
fooBarInstance.addEventListener(FooCloseEvent.FOO_CLOSE_EVENT,handleFooClose);
//But the compiler wouldn't like this....
fooBarInstance.addEventListener(FooOpenEvent.FOO_OPEN_EVENT,handleFooClose);
fooBarInstance.addEventListener(FooCloseEvent.FOO_CLOSE_EVENT,handleFooOpen);

Where this really helps code readability is when you want to include some sort of payload data with the event.   I won’t write the revised event classes out but think of the bar events from before.  If you rewrite them to include the constant in the event and the type is fixed to that constant.  This is what you end up with to dispatch the event .

import com.some.thing.foo.events.*

   //For BarEvent
   dispatchEvent(new BarEvent("iphoney"));

   //or for Bar2Event
   dispatchEvent(new Bar2Event("iphone home"));

Now that is much easier to read and understand.  Plus the advantage that I just mentioned above about the compiler catching incorrectly assigned event listeners comes into play even more when you have events that carry data.  For example; Imagine that you have an event with a “status” property, “status” would have quite a different meaning for an open event, close event and a delete event.  You would want to ensure that it is handled correctly.

Ok…. so this post has gotten pretty long and I haven’t even gotten to the meta data tag I mentioned before…. ok now I’m getting to that.

Basically it comes down to this.  You want to add the following meta data tag before the class definition for each event that your class will dispatch.  For example in my FooBarDispatcher class :

...
[Event(name="fooOpenEvent",type="com.some.thing.foo.events.FooOpenEvent")]
[Event(name="fooCloseEvent",type="com.some.thing.foo.events.FooCloseEvent")]
public class FooBarDispatcher Extends EventDispatcher
{
...

Now where this comes into play in FlashBuilder is in the auto sense type thingy.

FlashBuilder uses the information in the meta tag above to do a couple of things.  First it uses it to help you auto fill events that an object can dispatch.   So if I opened another class and created an instance of FooBarDispatcher named foosball (of type FooBarDispatcher)  as soon as I then typed the “(“ in “foosball.addEventListener(”    a list of the available events that could be dispatched by the object (fooOpenEvent, fooCloseEvent) would be displayed.

If I then select one of these events the other bit of magic happens.   Provided I have named my event name, event class, and event type constant correctly defined in the meta tag and the event class, FlashBuilder will automagically enter the correct class and constant value for me.  ie.    “FooOpenEvent.FOO_OPEN_EVENT” thus I then just have to type in the name of the event handler and all is done.    For reference ….

...
private var foosball:FooBarDispatcher = new FooBarDispatcher();
foosball.addEventListener(FooOpenEvent.FOO_OPEN_EVENT, handleFooOpen);
...

Now the rules for naming the event class, the event name and event type constant are the tricky bit  they are as follows.

  • The type in the meta tag must be point to the class that contains the constant.  This should also be the class of the event type itself.
  • The name in the meta tag must be the same as the name of the constant in the above class converted to all upper case where  an upper case letter is preceeded by an underscore as in…
    fooOpenEvent ->  FOO_OPEN_EVENT
    fooCloseEvent -> FOO_CLOSE_EVENT
  • To keep things simple and consistent, the string contained in the constant in the event class should be the reverse
    FOO_OPEN_EVENT = “fooOpenEvent”

That’s it.  Now I should mention that the above method of using the meta tag WILL work just fine with the method of having more than one event type defined in a single event class.  However I hope you see there are other very good reasons to define separate events for each event type.

The extra time it takes to create individual event classes and the time it takes to add the meta tag to your event dispatchers for all the events it dispatches does pay off.   First when you are coding by having the correct event types automatically appear and second by reducing debugging time since bone-headed event handling errors will be caught by the pre-compiler.

PS.  Another  thing this does, is show your events when you use your components in MXML. (If you swing that way.)

PSS.  Almost forgot (this is even more goodness)   By specifying the event meta data you can also add an ASDoc comment to  the event.   Maybe I’ll write a post about that too someday.

Advertisement

Leave a Comment

Filed under Adobe, AIR (Adobe Integrated Runtime), Flash, Flex

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s