The recent 7.2 update to Flash MX 2004 provides a new class, mx.utils.Delegate, that you can use to proxy events to different handlers and scopes. This article discusses the new class, its advantages, and how to use it.
To complete this tutorial you will need to install the following software and files:
Before reading this article, you should be familiar with component EventHandling in ActionScript 2. If you are not, I recommend that you see Using Events with Components.
While building the Macromedia XML News Aggregator (MXNA) Web Service Sample Application, one of the issues I encountered was that the ComboBox and DataGrid components both broadcast events named "change". This means that a single event handler handles events from multiple components—something that I normally don't like to do as it makes the code harder to maintain and understand. I could pass the event handler directly to the component, but then it would be called in the incorrect scope (within the component's scope and not my class's scope).
There are two solutions for this issue. The first is to use a switch statement
in my change event handler that checks the eventObt.target passed to the event
handler to see where the event came from, and then dispatch the call appropriately.
Here is an example of the code for this option:
myDataGrid.addEventListener("change", this);
myComboBox.addEventListener("change", this);
function change(eventObj:Object):Void
{
switch(eventObj.target)
{
case myDataGrid :
{
trace("myDataGrid's change event fired.");
break;
}
case myComboBox :
{
trace("myComboBox's change event fired.");
break;
}
}
}
Imagine how complex the code would be if you had other components also broadcasting
change events? I did not like this solution for the following reasons:
As I add more components with a change event, the function would become more and more complex and harder to maintain and follow.
Because of number one, I can probably just have each case call a specific function depending on which component broadcasts the event. This would essentially proxy the calls to its own event, but do so in a way that is not modular or reusable.
While this approach is not necessarily wrong, it can make your code harder to maintain, especially as your application grows.
The solution I ended up using (based on an idea by Samuel Neff) is a reusable class that acts as a proxy for my events, registering itself for specific events, and then proxying the calls to the event handler and scope I specify. This provides the following benefits and advantages:
change events from two different components to two separate methods.Of course, I was not the only one, nor the first one who encountered this issue. Developers within the Flash community began to create a number of different approaches and solutions. We needed a standard way to deal with this issue.
The recent 7.2 update to Macromedia Flash MX provides a new class, mx.utils.Delegate,
which gives developers a standard way to proxy events to the function and scope that
they want. The class provides a single static function called create that returns a
delegate function that you can use to proxy event calls.
Here is the signature for the Delegate.create function (a method signature is the
method name, its return type, and arguments):
static function create(scope:Object, handler:Function):Function
The scope parameter: The scope that the event is called within.
The handler parameter: The event handler function called
when the event is broadcast.
Basically, the class handles the event on behalf of the listener by invoking a different function. You can also specify the scope in which the function is called.
As you can see, the class returns a function that it uses to receive and ultimately proxy the broadcast event.
Look at the example below using the new mx.utils.Delegate class:
import mx.utils.Delegate;
myDataGrid.addEventListener("change",Delegate.create(this,onMyDataGridChange));
myComboBox.addEventListener("change",Delegate.create(this,onMyComboBoxChange));
function onMyDataGridChange(eventObj:Object):Void
{
trace("myDataGrid change event fired");
}
function onMyComboBoxChange(eventObj:Object):Void
{
trace("myComboBox change event fired");
}
Because each event handler manages a specific event from a specific component, the code is much easier to maintain and improves readability. An added benefit of using the Delegate class is that you can specify the scope that the handlers are called within.
Note that if you need to remove the listener at a later point, then you must change the code to store a reference to the delegate, as follows:
import mx.utils.Delegate;
var dataGridDelegate:Function = Delegate.create(this,onMyDataGridChange);
myDataGrid.addEventListener("change", dataGridDelegate);
function onMyDataGridChange(eventObj:Object):Void
{
trace("myDataGrid change event fired");
}
Then, you can remove the listener with this code:
myDataGrid.removeEventListener("change", dataGridDelegate);
Use the Delegate class by passing its return function as the second parameter of the addEventListener method for the component instance.
myDataGrid.addEventListener("change",Delegate.create(this,onMyDataGridChange));
Here is the signature for the addEventListener method:
componentInstance.addEventListener(event:String, listener:Object):Void
The event parameter: A string that specifies the name
of the event.
The listener parameter: A reference to a listener object
or function.
The second parameter is optional. If an object is passed to the method, the event
handler is called in the scope of that object. If a function is passed to the method,
the function is called to handle the event, but in the scope of the component. If no
second parameter is passed to the method, then the event is called in the scope of
the containing class and/or timeline (as if you had passed in this ).
So, in the code, you first specify that you want to listen for the change event from the component.
myDataGrid.addEventListener("change", ...));
Then, you create a delegate function using mx.utils.Delegate.create(), and specify
the function it returns as the function handler.
Delegate.create(this,onMyDataGridChange)
Again, the first argument specifies that the event is scoped to this (in this case
the containing class/timeline), and that the onMyDataGridChange function is called
to handle the event.
It is a very simple class, but can greatly help make your code easier to write and maintain. Furthermore, the more complex your code becomes, the more important using the Delegate class becomes as it allows you to provide one-to-one, event-to-event handler mappings, which makes your code much easier to maintain and follow.
Mike Chambers has spent the last eight years building applications that target the Flash runtime. During that time, he has worked with numerous technologies, including Flash, Generator, .NET, Central, Flex, and Ajax. He is currently the Principal Product Manager for developer relations for Adobe AIR. He has written and spoken extensively on Flash and rich Internet application development and is coauthor of the Apollo for Adobe Flex Developers Pocket Guide, Adobe Integrated Runtime (AIR) for JavaScript Developers Pocketguide, Flash Enabled: Flash Design and Development for Devices as well as Generator and Flash Demystified. Mike received his Masters in International Economics and European Studies from the John Hopkins School of Advanced International Studies (SAIS) in 1998. When he is not programming, Mike can be found playing Halo 2, trying to recover from his World of Warcraft addiction, or playing with his two daughters.