How to Raise Custom Events (EventDispatcher)

ActionScript 2.0

This article follows on the heels of How to Raise Custom Events (AsBroadcaster), so if the following paragraphs seem to move too quickly, you may want to read that one first.  To recap, the AsBroadcaster class provides a means to create custom events that may be subscribed to and acted upon by listener objects.  The mechanism it uses is relatively straightforward.

Another way to accomplish the same goal, only marginally more complicated, is provided by the EventDispatcher class.  (For what it’s worth, EventDispatcher is the class used by Flash’s v2 UI Components to raise events.  Kind of neat.) 

An answer, relatively short and sweet

Import the EventDispatcher class via its full path.  Doing this means you can refer to it in subsequent code without having to retype the mx.events prefix.

import mx.events.EventDispatcher;

Create an arbitrarily named variable, broadcaster, and use it to store a reference to an instance of the Object class.  The static EventDispatcher.initialize() method converts broadcaster into a bona fide broadcasting object.

var broadcaster:Object = new Object();
EventDispatcher.initialize(broadcaster);

Create another arbitrarily named variable, listener, and use it to store a reference to a second Object instance.

var listener:Object = new Object();

This listener will “hear” whatever events are sent to it.  In order to respond to these events, the listener must have a function assigned for each event raised.  Notice that parameters may be provided (see the onDropped function assignment, below).  With EventDispatcher, parameters arrive as properties of yet another object.  The function literal, below, accepts this third object as its only parameter, but this object may contain as many properties as you like, of any data type (even other objects!).  In this example, we’re only looking for one string property.

listener.onPickedUp = function() {
  trace("Picked up.");
};
listener.onDropped = function(evt:Object) {
  trace("Dropped on " + evt.msg + " side.");
};

Finally, invoke the EventDispatcher.addEventListener() method on the broadcaster object, supplying both the event to listen for (as a string), and the listener object as parameters.  The reason broadcaster knows how to perform this method is because EventDispatcher initialized it earlier.

broadcaster.addEventListener("onPickedUp", listener);
broadcaster.addEventListener("onDropped", listener);

As this point, use the EventDispatcher.dispatchEvent() method to raise the event(s) subscribed to the broadcaster object above elsewhere in your code.

dispatchEvent({type:"onPickedUp"});
broadcaster.dispatchEvent({type:"onDropped", msg:"right"});

Notice the shorthand way of instantiating a generic Object instance, {}.  That second example, onDropped, could be written like this …

var eventToSend:Object = new Object();
eventToSend.type = "onDropped";
eventToSend.msg = "left";
dispatchEvent(eventToSend);

… but the shortcut — the curly braces approach — requires less typing.

At minimum, you must supply a type property, which specifies the sort of event being raised (see the onPickedUp event), but understand that you may include whatever additional properties you need.

For a practical example, download EventDispatcher.fla (opens as far back as Flash MX 2004).  In the FLA file, you’ll find a draggable “ball” movie clip.  Its draggability is due to functions assigned to the MovieClip.onPress and MovieClip.onRelease events.  Note that these functions also invoke the EventDispatcher.dispatchEvent() method.

var halfway:Number = Stage.width / 2;
mcBall.onPress = function() {
  this.startDrag();
  broadcaster.dispatchEvent({type:"onPickedUp"});
};
mcBall.onRelease = function() {
  this.stopDrag();
  if (this._x < halfway) {
    broadcaster.dispatchEvent({type:"onDropped", msg:"left"});
  } else {
    broadcaster.dispatchEvent({type:"onDropped", msg:"right"});
  }
};

Another example is demonstrated in Part 2 of “Loading and Tracking Multiple Files at the Same Time” — probably a good idea to read Part 1 first.  Yet another is demonstrated in “How to Play a Timeline Backwards (with Easing!)

Additional reading

For an example of custom events raised from inside a custom class, see Kenneth Toley’s article at Adobe.com:

http://www.adobe.com/devnet/flash/articles/creating_events.html

10 Responses to “How to Raise Custom Events (EventDispatcher)”

  1. eRez Says:

    other than minor syntax differences, in what other way does eventDispatcher differs from the asBroadcaster?
    or in other words - when do i use this and when do i use the other?

  2. David Stiller Says:

    eRez,

    Really, the choice is yours. Personally, I prefer EventDispatcher, but that’s only because it sends an event object with optional arguments supplied as object parameters, rather than just as arguments. But really, that’s like saying I prefer coffee ice cream because it tastes like coffee, rather than vanilla.

    For what it’s worth, the v2 Components that ship with Flash use EventDispatcher — but honestly, just use the one that makes more sense to you.

  3. Dominic Turner Says:

    Hi there David,

    I have read your two articles about custom events and they have been really helpful and influenced me greatly in how I go about writing my flash projects. It is a much cleaner way of doing things than my current dodgy sub-movie loops to try and work out whether something has happened.

    However I have a problem that I don’t know if you can shed some light on. I am using the webserviceconnector class to connect to an asp.net webservice. Sometimes my webservice takes forever or hangs, and I would like to give the user a way of cancelling the webrequest.

    There don’t seem to be any methods for “abort” so I was thinking would it be possible to raise an event for the connector - i.e. raise an error event, so that I can stop it? If there is any other simpler way that you know of I would love to know - am scratching my head with this one…

    Many thanks - great article,

    Dom.

  4. Dominic Turner Says:

    Well - further to my last - there is no timeout property in Flash 8 either (although there is still a timeout faultcode??????) but i have been able to accomplish a cancel by using removeEventListener for the status and result events.

  5. David Stiller Says:

    Dom,

    Thanks for the kind words! :)

    As far as I know, there is not a way to cancel a web request in AS1/AS2 until it times out on its own (and you’re right, there is no timeout property — that has always baffled me). I seem to remember a Flashcoders workaround suggestion … something along the lines of requesting a new, known-good, very small file to “cancel” the pending request, but I’m afraid the details are hazy in my memory.

    I was about to suggest that you use setInterval() or setTimeout() [undocumented], when I saw your follow up post. ;) To my thinking, you’re on the right track. Good luck with that!

  6. Ed Hassinger Says:

    Flash sucks. As such you took a great topic and gave a concise example that someone using a real programming language/IDE could work with it quickly.

    Kudos.

  7. David Stiller Says:

    Ed,

    It sounds like we don’t have a whole lot in common, but I’m happy if this blog entry helped you.

    I enjoy the occasional venture into other territory, be it C#, Java, Python, PHP … I have my hunch which of the above you’d consider “real,” but in many ways, it’s just a matter of where and how you care to spend your time.

    I’m certainly thankful for developers who spend their efforts in lower level languages, because they allow me to do the things that float my boat. I’d say there’s plenty of elbow room for whoever wants to dive in.

    Have you checked out Flex and ActionScript 3.0? I think you’ll find there’s quite a difference.

  8. Michael de Nigris Says:

    David,

    Thanks for the informative article. I’ve successfuly implemented custom events with a class, but I’m having trouble dispatching an event from within an anonymous function (another event handler) within the class.

    For instance, this code does not seem to reach the listeners outside the class.

    MyXMLSocket.onData = function(sData:String){
    var eventObject:Object = {target:this, type:”onDataReceived”};
    this.dispatchEvent(eventObject);
    }

    Any clue what I’m doing wrong?

  9. David Stiller Says:

    Michael,

    What you’re seeing is the result of how that function is scoped. The global this property is scoped to the MyXMLSocket object by way of the anonymous function. Its “point of view,” therefore, is the MyXMLSocket object, which almost certainly doesn’t feature a dispatchEvent() method. Make sense?

    In a case like this the Delegate class is a good idea. Import import mx.utils.Delegate; before your class declaration, then replace that function with this …

    MyXMLSocket.onData = Delegate.create(this, function() {
      var eventObject:Object = {target:this, type:”onDataReceived”};
      dispatchEvent(eventObject);
    });

    What this does is re-route the scope of your function to the class itself, which does support a dispatchEvent() method, assuming you used EventDispatcher.initialize(this); in the constructor.

    Note: It didn’t appear you were using the sData parameter, so I dropped it.

  10. Michael de Nigris Says:

    Thanks David. Makes perfect sense, and your suggestion worked perfectly. By the way, I am using the data parameter, however, I had removed it during debugging attempts to simplify the problem.

    xsMCE.onData = Delegate.create(this, function(sData:String) {
    var eventObject:Object = target:this, type:”onDataReceived”, stream:sData};
    this.dispatchEvent(eventObject);
    });

    Thanks for the insight.

Leave a Reply