Today I found myself needing to trigger two functions in a button’s onRelease event handler. I wanted to keep the ability to install a handler function dynamically, just like you’d do when saying mc.onRelease = doSomething;, but I wanted to add the new function without displacing any previously installed handler. Also I hoped to keep the API simple. See what you think.
In my button’s constructor, I have some code that looks like this:
this.onRelease = FunctionChain.create(); this.onRelease.add(Proxy.create(this, this.broadcastSelectionEvent));
and later, in another part of the forest:
theButton.onRelease.add(buttonReleaseFunc);
And that’s it! When the button is clicked, both functions are triggered.
The FunctionChain class that makes this work is pretty simple, too:
import ascb.util.Proxy;
class com.nodename.utils.FunctionChain
{
static var version:String = "$Id: FunctionChain.as,v 1.1.1.1 2005/07/18 00:36:48 ashaw Exp $";
static function create():Function
{
return (new FunctionChain())._execute;
}
/**************************
* End of public interface!
*************************/
private var _functions:Array;
private var _execute:Function;
private function FunctionChain()
{
this._functions = [];
this._execute = Proxy.create(this, this.executeChain);
this._execute.add = Proxy.create(this, this.add);
}
private function executeChain():Void
{
var numFuncs:Number = this._functions.length;
for (var i:Number = 0; i < numFuncs; i++)
{
this._functions[i]();
}
}
// func had better be created by Proxy or Delegate!
private function add(func:Function):Void
{
this._functions.push(func);
}
}
Simple, yes, but the details may not be clear to everybody, so let’s take a look at the code. (If it’s all clear to you, just skip to the usage notes at the end.)
The heart of the class is just an Array of functions; the add(func) method just adds another function to the Array, and the executeChain() method executes each of the functions in turn. Nothing special there. It’s the stuff in the constructor and in the static create() method that lets us hide things away and simplify the API.
First the Array of functions is initialized to an empty Array. No problem. Then we set _execute, a Function variable, to refer to the executeChain method, but not directly. We use a Proxy, which carries a reference to the guy who’s going to execute the method as well as a reference to the method itself. This is important (stop me if you’ve heard this) because when the function finally gets called, we’re going to need to find that guy, and probably no one around is going to be pointing to him. And since it’s he himself who’ll be executing his own method, the method doesn’t have to be public.
The Proxy class is part of Joey Lott’s ascb library. Its usage is just like that of mx.utils.Delegate, except that Proxy also allows you to specify arguments that will be passed to the function when it runs. So I’ve gotten into the habit of using Proxy rather than Delegate.
OK, back to _execute. This, as I said, refers to the executeChain() method, which is just what we want our onRelease method in the button to do. We’ll be returning _execute to the button so he can set his onRelease handler to it. But there’s another piece we need to take care of, and that’s providing a way to add functions to the chain. So we create another Proxy, referring to the FunctionChain’s add() method, and we tack it right onto _execute. Remember in ActionScript a Function is an Object, so like any other Object it can take on properties — either data members or other Functions. (And since Function is a dynamic class, it can take on properties that were not declared in the class definition.) I believe it was pretty common to add properties to Function objects in AS1, but this is the first time I’ve found an excuse to do it in AS2.
So we’re going to return _execute to the button. We could provide an accessor method in FunctionChain, but we note that there’s really no need for the button to have a handle on the FunctionChain object at all, so we can just make the constructor private and wrap the whole interface up in one static function, create().
A couple of notes about usage:
First, it’s important that the functions you add to the FunctionChain also be created by Proxy or Delegate.
Second, you can use FunctionChain to build any function; there’s nothing about it that restricts it to Button or MovieClip event handlers.

