back

A beginner's guide to the Mate framework for Adobe Flex

by Brian Rinaldi

For the longest time, Cairngorm seemed to be the only viable lightweight Flex framework. Lately some new Flex frameworks have been growing in popularity. One of the newer frameworks that is gaining ground among bloggers and other Flex developers is Mate.

Created by Nahuel Foronda and Laura Arguello of AsFusion, Mate (pronounced mah-teh) is a tag-based, event-driven framework that focuses on giving developers maximum flexibility. In general, Mate is easy to learn. However, despite good documentation, its flexibility can often lead to a lot of questions, especially for new users. This article gets you started using the Mate framework and helps you build a simple application that uses Mate's core features.

Like other frameworks, Mate addresses the common architectural concerns in Flex such as event handling, data binding, and asynchronous processing. One way Mate differentiates itself is by utilizing the built-in event-driven nature of Flex applications rather than building a framework-specific event architecture. Another differentiator is that Mate is entirely tag-based. It focuses on easy-to-use and well-documented tags that handle common application tasks such as listening for events, sending remote object calls, and handling results. Much of this is managed within Mate's concept of an EventMap, which routes the application flow, defining, for example, what the responses to particular events will be, how remote object responses are handled, and which values are injected into particular views. If this sounds intimidating, don't worry; it's actually quite straightforward, and it will become clearer as we walk through our sample application.

Getting started

The sample application I use in this article is the Upcoming.org API. Upcoming.org is a site that enables people to post and share events in their local area. The API, which is currently for nonprofit use only, provides access to event information through various search options. For this example, I implement a location-based search in which I can specify a country, state, and metropolitan area to filter the event results from the site. I populate the country, state, and metro ComboBoxes with data from the site and then fill a DataGrid with the search results. Clicking the DataGrid row populates a simple dialog box with the full event details.

For the back end of this application, I use Adobe ColdFusion. ColdFusion is arguably the easiest way to connect Flex to a data-driven back end because it comes with Flash Remoting and allows for automatic translation of types, including objects, back and forth between Flex and ColdFusion. The ColdFusion code is relatively simple. It includes a service, a facade, and a handful of value objects. Because this article isn't focused on ColdFusion, I do not discuss the code in detail, and ColdFusion knowledge is not a prerequisite for this tutorial.

You can download the code for the sample application via Subversion at http://code.google.com/p/remotesynthesis.

Admiring the view

Our view is made up of three components: the main MXML file (main.mxml); a panel to select your country, state, and metro area (/com/view/MetroSelector.mxml); and another panel that contains the DataGrid of event results and the Event Details panel (/com/view/EventPanel.mxml). If I were going to expand on this application, I would have separated portions of the view into more specialized components, but for the sake of this example, I'm keeping it simple.

If you examine the code of these components, you may notice that other than including the MainEventMap in main.mxml, there is no other reference to the Mate framework in the application's views. This makes it very easy to reuse views created for a Mate application, which is one of the many benefits of the Mate framework.

Creating events about upcoming events

The Mate framework does not require a specialized event class or event dispatcher. Thus, if you look at the events in the sample application, you'll notice that they are all standard Flash events and extend flash.events.Event. They also bubble up the display list hierarchy as Flash events do. Once again, this helps promote reuse while eliminating boilerplate and tight coupling with a specific framework.

In the following code, you can see that the SearchEvent class is just a basic Flash event that has a static class representing the event type and four properties called searchText, countryId, stateId, and metroId:

package com.events
{
    import flash.events.Event;

    public class SearchEvent extends Event
    {
        public static const SEARCH: String = "search";
        
        public var searchText : String;
        public var countryId : Number;
        public var stateId : Number;
        public var metroId : Number;
        
        public function SearchEvent(type:String, bubbles:Boolean=true, cancelable:Boolean=false)
        {
            super(type, bubbles, cancelable);
        }

    }    
}

This event is announced when users submit the search form. To dispatch this event, first set the property values for the various form fields and then simply use the dispatchEvent() function, as shown in the following code:

private function doSearch(e:Event):void {
    var event:SearchEvent = new SearchEvent(SearchEvent.SEARCH); 
    event.countryId = countrySelector.selectedItem.id; 
    event.stateId = stateSelector.selectedItem.id; 
    event.metroId = metroSelector.selectedItem.id; 
    dispatchEvent(event);
} 

The EventMap and mapping events

Now that you have created an event and dispatched it, you need to respond to it to perform some kind of function. This is where you get into the guts of the Mate framework and the EventMap. The EventMap is an MXML file that, among other functions, defines how your application responds to particular events via EventHandlers or MessageHandlers. (MessageHandlers are used for working with the Flex Messaging Service, which is not covered in this article.) EventHandlers can invoke any number of actions, including remote method calls, methods within the Flex application, or even other events. Your application does not need to be limited to a single EventMap and, in fact, using a single EventMap for large applications is not recommended.

It is important to note that while most of your EventHandler definitions will be responding to one of your own custom event types, Mate can respond to built-in Flex events. For example, in this application we need to populate the country and state ComboBoxes when the application loads. Therefore I added an EventHandler for the FlexEvent.APPLICATION_COMPLETE event, which is announced when the application has finished initializing. In this particular EventHandler, I simply announce other events that are designed to retrieve the country and states from the ColdFusion service. The only difference is that calling the states list requires a country to be specified; therefore you need to pass a default value that is defined as a constant in the CountriesEvent. This enables you to preselect United States instead of simply preselecting the first country on the list:

<EventHandlers type="{FlexEvent.APPLICATION_COMPLETE}">
    <EventAnnouncer generator="{CountriesEvent}" type="getCountries" />
    <EventAnnouncer generator="{StatesEvent}" type="getStates">
        <Properties countryId="{CountriesEvent.DEFAULT_COUNTRY}" />
     </EventAnnouncer>
</EventHandlers>

In this sample application, each of the custom events is tied to a RemoteObject call to a CFC method. As discussed earlier, this application has a single ColdFusion component with remote methods intended for the Flex application. To simplify calling this component throughout the EventMap, the following is defined at the top of the EventMap mxml:

<mx:RemoteObject id="upcomingRemote" destination="ColdFusion" source="org.upcoming.upcomingRemote" /> 

The SearchEvent has a constant called "SEARCH," which defines the event type of "search." When a user submits the search form, it dispatches the SearchEvent with this type defined. Thus, the EventHandlers can bind to this constant as well, allowing it to respond when this event is announced. For this event, make a RemoteObject call to a method on the CFC called search() to which you will pass the four properties of your event. You must also define a resultHandler that states that when the results are returned, the setUpcomingEvents() method on the Manager class will be invoked:

<EventHandlers type="{SearchEvent.SEARCH}">
    <RemoteObjectInvoker instance="{upcomingRemote}" method="search"
         arguments="{[event.searchText,event.countryId,event.stateId,event.metroId]}">            <resultHandlers>
                <MethodInvoker generator="{UpcomingManager}"
                method="setUpcomingEvents"
                arguments="{resultObject}"/>
        </resultHandlers>
    </RemoteObjectInvoker>
</EventHandlers> 

Confronting your Manager

Within Mate, your Manager classes contain the nitty-gritty of your Flex application, so let's take a closer look at them. The Manager class in Mate is similar in some respects to a command class in Cairngorm. However, the Mate Manager class isn't tied to a particular event and, in fact, can handle any business logic or processing required within any number of events. How you organize your Manager classes is up to you. Additionally, your Manager class will generally contain properties that, using the Mate EventMap, you can bind to your views, but more on that later.

Your application is pretty simple, so it only has a single Manager class with a handful of properties and methods. These methods all simply serve the purpose of saving the result from a remote call and setting it as a property within the instance of your Manager class. Obviously within a larger, real-world application, your Manager would be more complex than this:

package com.business
{
    import com.vo.metro.*;
    import com.vo.upcomingEvent.UpcomingEvent;
    
    import mx.collections.ArrayCollection;
    
    public class UpcomingManager
    {
        
        [Bindable]
        public var countries:ArrayCollection = new ArrayCollection();
        
        [Bindable]
        public var selectedCountry:Country; // this is mostly here for compile purposes to enable CF type translation
        
        [Bindable]
        public var upcomingStates:ArrayCollection = new ArrayCollection();
        
        [Bindable]
        public var selectedState:UpcomingState; // this is mostly here for compile purposes to enable CF type translation
        
        [Bindable]
        public var metros:ArrayCollection = new ArrayCollection();
        
        [Bindable]
        public var selectedMetro:Metro; // this is mostly here for compile purposes to enable CF type translation
        
        [Bindable]
        public var upcomingEvents:ArrayCollection = new ArrayCollection();
        
        [Bindable]
        public var selectedEvent:UpcomingEvent; // this is mostly here for compile purposes to enable CF type translation
        
        public function setCountries(r:Array):void {
            countries.source = r;
        }
        
        public function setSelectedCountry(country:Country):void {
            selectedCountry = country;
        }
        
        public function setUpcomingStates(r:Array):void {
            upcomingStates.source = r;
        }
        
        public function setSelectedState(myState:UpcomingState):void {
            selectedState = myState;
        }
        
        public function setMetros(r:Array):void {
            metros.source = r;
        }
        
        public function setUpcomingEvents(r:Array):void {
            upcomingEvents.source = r;
        }
    }
}

Injecting properties into the view

Now that you've received data from your remote call and processed that result, your next task is to get that data to the portions of your view that require it. Mate's approach uses dependency injection, which helps keep your views independent from your framework. You tell Mate which properties from which Managers are needed in a particular view component, and Mate injects them into the view for you.

For example, the EventPanel.mxml component displays the DataGrid for the event results returned by Upcoming.org for our search. This uses the upcomingEvents property of the UpcomingManager class that was populated with the RemoteObject result, as seen in the earlier code. To make this available to the EventPanel.mxml component, you need to define an Injectors tag block within your EventMap with a PropertyInjector to supply the source (our ManagerClass property) and the destination (a property within our view component), as you can see in the following code:

<Injectors target="{EventPanel}">
    <PropertyInjector targetKey="upcomingEvents" source="{UpcomingManager}"
        sourceKey="upcomingEvents" />
</Injectors>

Within your view, you have a bindable public property called upcomingEvents into which the value is injected:

[Bindable]
public var upcomingEvents:ArrayCollection; 

Now your view can simply bind to the local public property for "upcomingEvents." As you can see in the DataGrid:

<mx:DataGrid id="eventsGrid" width="99%" height="0" x="2" y="2" dataProvider="{upcomingEvents}" itemClick="setSelectedEvent();closeGrid(event)">
    <mx:columns>
        <mx:DataGridColumn headerText="Event Name" dataField="eventName" />
        <mx:DataGridColumn headerText="Start Date" dataField="startDate" labelFunction="formatDateColumn" />
        <mx:DataGridColumn headerText="Price" dataField="ticketPrice" />
    </mx:columns>
</mx:DataGrid> 

Responding to events in the view

Mate provides a built-in way to add a listener to your views called a ListenerInjector, which enables your views to react to events announced within the EventMap or elsewhere. In some cases, this isn't necessary because Mate events are regular Flash events and you can naturally respond to Flash events within your Flex application. Nonetheless, this can be useful in cases where the event doesn't specifically bubble up to the necessary component (when announcing events from within the EventMap, for example).

For the sample application, the default country should be selected once the country list is populated with the result from your RemoteObject call. To do this, you must first announce an event of type countriesReceived within your EventMap when the countries results are received using the Mate tag EventAnnouncer:

<EventHandlers type="{CountriesEvent.GETCOUNTRIES}" debug="false">
    <RemoteObjectInvoker instance="{upcomingRemote}" method="getCountryList" debug="false">
        <resultHandlers>
            <MethodInvoker generator="{UpcomingManager}"
                method="setCountries"
                arguments="{resultObject}"/>
            <EventAnnouncer generator="{CountriesEvent}" type="countriesReceived" />
        </resultHandlers>
    </RemoteObjectInvoker>
</EventHandlers>

Next, you need to register a ListenerInjector within the Injectors block for the MetroSelector component. This adds an event listener specifically to the MetroSelector.mxml component that sets the default country value:

<Injectors target="{MetroSelector}">
    <ListenerInjector method="setDefaultCountry" eventType="{CountriesEvent.COUNTRIESRECEIVED}"/>
</Injectors>

This method in the MetroSelector.mxml simply ensures that the selected value on the ComboBox is set to the default value:

private function setDefaultCountry(event:Event):void {
    for (var i:Number = 0; i < countries.length; i++) {
        if (countries[i].id == CountriesEvent.DEFAULT_COUNTRY) {
            countrySelector.selectedIndex = i;
            break;
        }
    }
} 

Conclusion

I have only scratched the surface of the features the Mate framework offers. While I didn't have a chance to discuss built-in debugging support in the EventMap, the integrated support for Cairngorm classes to ease the transition of converting existing applications, or the handling of Flex Messaging, I hope this article conveys the ease-of-use and flexibility that Mate provides. Working with Mate has only enhanced my enjoyment of working in Flex, and I hope this article gets you started. The next step is simply to try it for yourself.

References

The following are some useful resources to help you learn more about Mate and other Flex frameworks:

‹ Back


Brian Rinaldi is as a Content and Community Manager for the Adobe Developer Center team, where he helps drive content strategy for HTML5 and JavaScript developer content. Brian blogs regularly at http://remotesynthesis.com and is a unreformed twitter addict @remotesynth.