I love the AS3 event model - it helps keep my code clean and lossely coupled. When I used to work on AS2 projects, my code was not so neat and classes were more reliant on one another. Due to AS2's strange handling of scope I never really got on with the AS2 event system.
As I still occasionally have to work in AS2, my question is:
Has anyone managed to simulate the AS3 event API in AS2, and if not, what is the best practice for listening to and dispatching events and handling scope?
Its quite easy to do this, actually. A couple of classes should get you going. The first being an Event
class, as follows:
class com.rokkan.events.Event
{
public static var ACTIVATE:String = "activate";
public static var ADDED:String = "added";
public static var CANCEL:String = "cancel";
public static var CHANGE:String = "change";
public static var CLOSE:String = "close";
public static var COMPLETE:String = "complete";
public static var INIT:String = "init";
// And any other string constants you'd like to use...
public var target;
public var type:String;
function Event( $target, $type:String )
{
target = $target;
type = $type;
}
public function toString():String
{
return "[Event target=" + target + " type=" + type + "]";
}
}
Then, I use two other base classes. One for regular objects and on for objects that need to extend MovieClip
. First the non MovieClip
version...
import com.rokkan.events.Event;
import mx.events.EventDispatcher;
class com.rokkan.events.Dispatcher
{
function Dispatcher()
{
EventDispatcher.initialize( this );
}
private function dispatchEvent( $event:Event ):Void { }
public function addEventListener( $eventType:String, $handler:Function ):Void { }
public function removeEventListener( $eventType:String, $handler:Function ):Void { }
}
Next the MovieClip
version...
import com.rokkan.events.Event;
import mx.events.EventDispatcher;
class com.rokkan.events.DispatcherMC extends MovieClip
{
function DispatcherMC()
{
EventDispatcher.initialize( this );
}
private function dispatchEvent( $event:Event ):Void { }
public function addEventListener( $eventType:String, $handler:Function ):Void { }
public function removeEventListener( $eventType:String, $handler:Function ):Void { }
}
Simply extend your objects with either Dispatcher or DispatcherMC and you will be able to dispatch events and listen for events similarly to AS3. There are just a few quirks. For example, when you call dispatchEvent()
you have to pass in a reference to the object dispatching the event, usually just by referring to the object's this
property.
import com.rokkan.events.Dispatcher;
import com.rokkan.events.Event;
class ExampleDispatcher extends Dispatcher
{
function ExampleDispatcher()
{
}
// Call this function somewhere other than within the constructor.
private function notifyInit():void
{
dispatchEvent( new Event( this, Event.INIT ) );
}
}
The other quirk is when you want to listen for that event. In AS2 you need to use Delegate.create()
to get the correct scope of the event handling function. For example:
import com.rokkan.events.Event;
import mx.utils.Delegate;
class ExampleListener
{
private var dispatcher:ExampleDispatcher;
function ExampleDispatcher()
{
dispatcher = new ExampleDispatcher();
dispatcher.addEventListener( Event.INIT, Delegate.create( this, onInit );
}
private function onInit( event:Event ):void
{
// Do stuff!
}
}
Hopefully I copied and pasted all this correctly from my old files! Hope this works out for you.
I would guess the best practice would be to use the EventDispatcher class where ever posible. You can read about it here:
http://help.adobe.com/en_US/AS2LCR/Flash_10.0/help.html?content=00002325.html
The UI components also have very AS3-like event dispatching.
I wrote a few classes for dealing with events in AS2. You can download them here.
http://dispatchevent.org/mims/as2-eventdispatcher/