| Blog Home | About | Entries By Date | Search |
|
Title
Mate -- An Event Based Flex Framework
Entry
Mate (pronounced mah-teh)-- a tag-based, event-driven Flex framework, created by Nahuel Foronda and Laura Arguello of AsFusion. Flex applications are event-driven. Mate framework has been created to make it easy to handle the events your Flex application creates. Mate allows you to define who is handling those events, whether data needs to be retrieved from the server, or other events need to be triggered. Mate provides a mechanism for dependency injection to make it easy for the different parts of your application to get the data and objects they need.
Image
More
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 differentiators 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.
Mate is design to take advantage of MXML and regular old Flash events dispatched the regular way, not through the framework like Cairngorm or Swiz (although Swiz is open to regular event dispatching if you set it up yourself). In that way it’s like PureMVC. But Mate uses the fact that part of the framework is defined right at Application level to make the event-driven part of the framework very unobtrusive and easy.
Since it’s very unobtrusively event based (you’ll see what I mean in a bit) it allows you to make a very componentized application easily, and although of course you can use the classes from the framework in ActionScript form, you’ll be surprised at how much you can do right in MXML.
Getting Started:
All Mate projects must have:
1. One or more events (custom or built-in)
2. One or more Event Maps
Typically, the basic steps to create a Mate project are:
1. Add the compiled framework code to your project (Mate.swc).
2. Create a file that will be the EventMap .
3. Include the event map in your main Application file.
4. Create a custom event.
5. Somewhere, dispatch that event.
6. Add EventHandlers in your event map that listen for the event type you dispatched.
7. Execute some actions inside the EventHandlers block (ie: call the server, store data, etc).
8. Repeat 4-7 for every event you need.
In Flex Builder, create a new Flex project called "LoginExample". Let the main source folder be "src"
(default folder).
In the libs folder it creates, place the compiled framework SWC (Mate.swc). This will let you use all Mate classes
and tags.
Every Mate project is driven by events. In the Login example, when the user enters the user name and password and clicks on the "Submit" button, we'll create a new event containing that information that will be sent to the
server. Therefore, we need to create a custom event to indicate that the user wants to submit the user name, password and retrieve success from server.
Our event will be very simple and it will contain two property: userName, password
package com.mate.loginExample.events
{
import flash.events.Event;
public class LoginEvent extends Event
{
public static const GET: String = "getLoginEvent";
public var userName : String;
public var password : String;
public function LoginEvent(type:String, bubbles:Boolean=true,
cancelable:Boolean=false)
{
super(type, bubbles, cancelable);
}
}
}
The code above assumes this event is contained within the package: com.mate.loginExample.events
The event also contains a constant that we will use to specify the event type. One event can specify more than
one event type. We also make this event bubble up by default (the second argument of the constructor). Otherwise, we will need to remember to specify it when we instantiate it.
Creating the UI
The user interface will only need two text inputs, one for User Name and other for Password entry and a button to submit:
Dispatching the LoginEvent
When the user clicks the 'Submit' button, we'll create the LoginEvent and dispatch it:
import com.mate.loginExample.events.LoginEvent;
private function getLogin() : void {
var loginEvent: LoginEvent = new LoginEvent(LoginEvent .GET);
loginEvent.userName = username.text;
loginEvent.password = password.text
dispatchEvent(loginEvent);
}
The Event Map
The EventMap is where we place the handlers for all the events the application creates (there could be more than one event map, though).
To add the event map, we need to create a new MXML file, with name "MainEventMap". This component must extend from EventMap . At this point, the event map would be empty and it should look like this:
<?xml version="1.0" encoding="utf-8"?>
<EventMap xmlns:mx="http://www.adobe.com/2006/mxml" xmlns="http://mate.asfusion.com/">
</EventMap>
Note: we use no namespace for http://mate.asfusion.com so that we don't have to add it to every tag in the
event map. You can copy the code above to your file as a starting point.
We'll add the event map to our main Application file:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"
xmlns:maps="com.asfusion.mate.stockQuoteExample.maps.*">
<maps:MainEventMap />
</mx:Application>
Listening for LoginEvent.GET
In our event map, we will listen for the quote event so that we can send the request to the server.
We'll add an EventHandlers tag that will specify the event type we are listening to. We'll also set the debug attribute to true so that we can see when the handlers run in the debugging output window.
<EventHandlers type="{LoginEvent.GET}" debug="true">
</EventHandlers>
At the top of the event map we'll need to import the event class.
<mx:Script>
<![CDATA[
import com.mate.loginExample.events.LoginEvent;
]]>
</mx:Script>
Inside this EventHandlers block, we'll place the actions we want to perform when the event is dispatched. In this case, we would like to make a server call, for which we'll use the RemoteObjectInvoker tag. Assuming the service in a folder called loginExample and it is called LoginService, you will specify the call as follows:
<RemoteObjectInvoker destination="ColdFusion" source="loginExample.LoginService"
method="getLogin"
arguments="{event.userName},{event.password}"
debug="true">
</RemoteObjectInvoker>
We are calling the method getLogin on that service and sending the symbol coming from the event as an argument of the remote method call.
Handling the server result
The server returns a numerical value with the stock's current price. We will handle that result inside the
RemoteObjectInvoker 's resultHandlers and call the function "loginStatus" on the LoginManager class.
<EventHandlers type="{LoginEvent.GET}" debug="true">
<RemoteObjectInvoker destination="ColdFusion"
source="loginExample.LoginService"
method="getLogin"
arguments="{event.userName},{event.password}"
debug="true">
<resultHandlers>
<MethodInvoker generator="{LoginManager}"
method="loginStatus" arguments="{resultObject}"/>
</resultHandlers>
</RemoteObjectInvoker>
</EventHandlers>
If you have shared data that many views will access, you may want to create a "model". In this simple example, you don't really need a model, but because it is something you will usually need, we'll add it anyway. Inside the resultHandlers, we are using a MethodInvoker to create an instance of LoginManager (if it doesn't already exist) and then call the method loginStatus. Inside the resultHandlers, we can access the result coming from the server, which we can pass as the argument of the method call.
Creating our Model, the LoginManager
The LoginManager will handle the business logic that has to do with login. It will also store the current login status so that it can be used by views. In the previous section, we were calling the method loginStatus(status) that stores the value of the login status. The class definition for this manager is:
package com.mate.loginExample.business
{
public class LoginManager
{
[Bindable]
public var currentStatus:String;
public function loginStatus(status:String):void {
currentStatus = status;
}
}
}
Ideally, the currentStatus property would be read-only instead of public. But in order to do that and still making it bindable, we will need to do some additional work.
Also, when the method loginStatus is called, we can execute any necessary business logic.
Showing the current price value in the view
So far, when the event is dispatched, we make a service call, the server returns the current login status and that status is stored in the LoginManager. But now we need to be able to show that value in the view.
In the view where we want to show the price, we'll add a property:
[Bindable]
public var status:String;
and then show that number anywhere in the view we want, for example, in a Label:
<mx:Label text="Login Status: {status}" />
That's all we need in the view.
Getting the current price from the model Manager to the view
But how does the view get this variable populated from the status stored in the LoginManager?
In our event map, we'll add another set of tags. These tags will assign a property on the model to a property on the view, and because the property on the model is bindable, the view will always get the most current value.
<Injectors target="{LoginPanel}">
<PropertyInjector targetKey="status" source="{LoginManager}" sourceKey="currentStatus"
/>
</Injectors>
When you add this, make sure you have all the necessary import statements at the top of your event map.
Overall Thoughts:
Mate does a great job of accomplishing its purpose, and I especially like that the only place you'll find Mate code is in the EventMap. Otherwise, my code was completely spotless, with each class having its own concerns and not at all worried about how to get information to and from other parts of the program. Some developers have reported that they don't like debugging with Mate, but I think they have done a great job with the Debugger. I found the errors to be easily intelligible so that I could find and fix the problem without much of a fuss.
That being said, there were a number of things that made me pretty uncomfortable using Maté. Possibly some of those issues are just my inexperience with frameworks in general and this one in particular, but I found them worth mentioning.
A script block just for imports. A Mate EventMap is primarily MXML. But because it winds up binding to Class names and static constants, you have to have import statements pointing to every class you reference. This means a Script tag whose sole function is to facilitate these imports. You can "import" the classes by hand typing a mx:Class tag without code assistance, but this gives you no help with code hinting, and, since you have no code hinting, involves more typing than using the Script tag. I think this is a problem more with MXML than Mate, but it's a pain when you're using MXML in a way that's "out of the box" compared to what Adobe was apparently thinking when they decided how MXML was going to work.
Lack of type safety/code hinting. Since you're not using a variable of a specific type and your argument or key property is separated from the Class name, you get zero help from code hinting, and of course the compiler does not warn you if you have made a mistake. This burns up a lot of time looking back and forth between the EventMap and the documentation or code to make sure you've entered values of the right type in the right place. Mysteriously, even some parts of the Mate framework don't show up in code hinting in the EventMap, such as scope.dispatcher.
Over dependence on binding. Mate works most easily and most intuitively if you use binding, which can cause a significant performance hit. To some extent, you can mitigate this by dispatching your own binding events, but I found at least one place where this didn't seem to work. I'm not sure if it was my mistake or if something in Mate or Flex binding was specifically listening for "propertyChange," but I finally had to remove the custom event and the dispatchEvent call for that one property. A binding problem can be very difficult to debug even if you're not using Mate.
Difficulty of figuring out how to reference things. I think this is definitely my own inexperience with the framework, but I found it difficult to figure out how to get a handle on how to tell Mate which object I wanted operated on. In an application that's more complicated than my example, with multiple instances of the same Class that you needed to read from, I don't know how you would nail down exactly which one you wanted. Potentially you could create methods on your EventMap (or static functions elsewhere) to inspect objects and tell you whether to proceed or not, but that strikes me as very "unMate."
Keywords
Mate frameworks, Event Based Flex framework