Events

A fundamental part of Mate are the events, since all communication between the different parts of the application is made via events.

The EventHandlers in the EventMap subscribe to listen to events of particular types. The type specified is very important because it will determine whether or not a sequence must be run. This type is a string and that string must be unique throughout your whole application.

We define this type as a constant in the event itself. Suppose you have an event called CustomerEvent:

import flash.events.Event;

public class CustomerEvent extends Event {

                  public function CustomerEvent(type:String, bubbles:Boolean=true, cancelable:Boolean=true) {

                  super(type, bubbles, cancelable);

                  }

}

We add a constant for the event type:

public static const ADD:String = "addCustomerEvent";

In our event map, then, we can use this constant as the event type. This helps us not making mistakes when typing the event type.

<EventHandlers type="{CustomerEvent.ADD}">
   .....
</EventHandlers>

You can use the same in your view Listeners:

<mate:Listener type="{CustomerEvent.ADD}" ..../>

And in your dispatchers:

<mate:Dispatcher generator="{CustomerEvent}" type="{CustomerEvent.ADD}" ...>

Creating a unique type

Since the event type must be unique, you can append the name of your event class so that it will be less likely to conflict with other events:

"add" + "CustomerEvent"= "addCustomerEvent"

public static const ADD:String = "addCustomerEvent";

If you want to ensure there are no conflicts, you can also use the full package name as part of the event type:

public static const ADD:String = "com.mydomain.events.CustomerEvent.ADD";

The above approach is not recommended if this event is a view event declared by the Event metatag in the view, as it will make the type too large and unreadable in parent views that wish to add event handlers for that event.

Having several types in the same event

You can have more than one type in the same event. As long as all those types defined use and need the same properties, they can be put together. For example, adding, updating and removing a customer all need a customer property and it makes sense to create only one event for all those types (assume you have a class Customer):

public class CustomerEvent extends Event {

                  public static const ADD:String = "addCustomerEvent";

                  public static const UPDATE:String = "updateCustomerEvent";

                  public static const DELETE:String = "deleteCustomerEvent";

                  public var customer:Customer;

                  public function CustomerEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=true) {

                  super(type, bubbles, cancelable);

                  }

}

Bubbling property

When an event has it "bubbles" property set to false, only listeners added explicitly to the object that dispatched the event will be notified when the event is dispatched.

If you use the view's dispatchEvent() function (every Display Object is a Dispatcher) and dispatch the event as you would normally do:

var myEvent:CustomerEvent = new CustomerEvent(CustomerEvent.ADD);
dispatchEvent(myEvent);

the event map will not be notified unless you set the event property bubbles to true. Just so that you don't have to remember this every time you create an event:

new CustomerEvent(CustomerEvent.ADD, true)

you can set this property as true by default in your constructor:

public function CustomerEvent(type:String, bubbles:Boolean=true, cancelable:Boolean=true)

and then this code will work fine:

var myEvent:CustomerEvent = new CustomerEvent(CustomerEvent.ADD);
dispatchEvent(myEvent);

Built-in Events

An EventHandlers block can listen to any event that bubbles up or that has been dispatched by using the EventAnnouncer tag. Any Flex built-in event can also be used as long as it bubbles up. For example, an EventHandlers block can listen to FlexEvent.APPLICATION_COMPLETE event.

dispatchEvent() vs dispatcher.dispatchEvent()

If you need to dispatch an event that should reach the Event Map, in most cases, you can simply use dispatchEvent() function that is available in every display object (ie: views). In those cases, you would simply instantiate an event, and then dispatch it using the dispatchEvent(myEvent) function. For example:

var myEvent:CustomerEvent = new CustomerEvent(CustomerEvent.ADD);
dispatchEvent(myEvent);

If you want to dispatch an event that should reach the event map from an object that is not in the display list (for example a Manager or a Presentation Model object), then you need to supply the dispatcher. Even if those objects extend EventDispatcher or implement the IEventDispatcher interface, the events they dispatch do not bubble up (even if the bubbles property is set to true) because they are not in the display list. When you instantiate a manager or presentation model object, you need to pass the dispatcher. This dispatcher is a global dispatcher when using an EventMap or it can be any other dispatcher when using LocalEventMaps.

You can pass the current dispatcher via the constructor or as a property. If you use the constructor, then it should expect to receive an argument of type IEventDispatcher:

private var dispatcher:IEventDispatcher;

public function CustomerManager(dispatcher:IEventDispatcher)
{
   this.dispatcher = dispatcher;
}

You will then use this.dispatcher to dispatch events from your manager.

You should instantiate your object (ie: manager or presentation model) as follows:

<ObjectBuilder generator="{CustomerManager}" constructorArguments="{[scope.dispatcher]}"/>

If you don't want to change the constructor, you can simply set a public property:

public var dispatcher:IEventDispatcher;

public function CustomerManager()
{
}

and instantiate the object as follows:

<ObjectBuilder generator="{CustomerManager}">
<Properties dispatcher="{scope.dispatcher}"/>
</ObjectBuilder>

3 responses

  1. I have some events beings dispatched from my model when properties change, and I'm wondering the best way to go about bubbling them up to the EventMap? The model is injected into the view via my manager class so it's a bit messy listening and then passing the event along from the view. I tried also listening in my manager class to the property change event on the model, then just dispatching again, but my event map doesn't see it. Also, fyi, the bubbles property is set to true when the event is dispatched from the model.

    Thanks!

    PS I posted in the comments instead of the forum because I think it may be useful to others reading the docs.
  2. RE "Creating a Unique type", this one just bit me because I didn't RTFM, or at least not this page. I had been assuming that "types" were qualified by the event's class (e.g., CustomerEvent). While the approach outlined in the article is workable in some apps, it may not be workable with larger apps when all the source code isn't under the control of the same group, following the same conventions. Is there a technical reason why an event's class can't be used by Mate to disambiguate the type?
  3. Rich,
    The class cannot be used to disambiguate the type because when you say CustomerEvent.ADD, for example, you are only specifying a static variable, which translates to "addCustomerEvent". Those are simply static vars, so we only see the value. Also, that is how Flex works. The function addEventListener, which is what we use in the event handlers, takes a string as a first argument. There is nothing else you can specify there to make any distinction.

Comments now closed