Creating a custom event listener in AS3

Published:
I come across a lot of question about how to access things in the document class from a movieclip, or accessing something from a movieclip in the document class.

It took me a while to figure this out but once I did it makes life so much easier.

By creating a CustomEvent class and placing it in your own utils folder and setting up your AS3 class path, once you import the Custom Event, this is how you'd go about it.

your class would look something like this ...

package whatever.utils //change your package name as required
{
 import flash.events.Event;

    public class CustomEvent extends Event
    {
       
      public static const NOTIFY:String = "notify";
        public var data:*;
            
       public function CustomEvent(type:String, data:*,  bubbles:Boolean = false, cancelable:Boolean = false){
                  super(type, bubbles, cancelable);
            this.data = data;
        }
    }
}

to implement

say you have a nested movieclip that when it hits frame 5 you want to execute a function in the document class called callSomething();

when you add the movieclip in your document class

addChild(nameOfMovieClip);
//add the dispatcher

nameOfMovieClip.addEventListener(CustomEvent.NOTIFY, handleNotifyRoot);

//note the CustomEvent.NOTIFY part - you can add items in your CustomEvent class

Create a handleNotifyRoot method in your document class

function handleNotifyRoot(e:CustomEvent):void
{
trace(e.data.myData.toString());
}

in the movieclip when you want the event to trigger, you must dispatch the event

var varString:String = "clicked ball";
dispatchEvent(new CustomEvent(CustomEvent.NOTIFY, {myData:varString}));



you can pass anything to your custom event.

I hope this all makes sense.
2
7,455 Views

Comments (9)

Top Expert 2009

Author

Commented:
:-) will mail you.

Commented:
blue-genie,

I just noticed they finish in Johannesburg on the 11th, then open in Cape Town on the 14th. So, if Johannesburg is better for you shoot me that email soon!

AreDubya

Commented:
Hi Blue-Genie,

Thumbs up for addressing custom events - too few know about this.
I have a few comments though.

1) I prefer using whatever.events - this is more aligned with the flash namespace structure
2) I like to use get and set functions - this way you can make data read-only
3) In most cases I would make the data value optional (data:*=null)
4) You should always override the clone and toSrting methods

While 1-3 is my personal likings the 4'th isn't.

// clone example:
var event1:CustomEvent=new CustomEvent(CustomEvent.NOTIFY, {name:"foo", value:bar });
var event2:CustomEvent=event1.clone()
trace(event1.data); // returns [object Object]
trace(event2.data); // without the override clone this will cause an error

// toString example:
var event:CustomEvent=new CustomEvent(CustomEvent.NOTIFY, {name:"foo", value:bar });

addEventListener(CustomEvent.NOTIFY,customEventHandler,false,0,true);
dispatchEvent(event)

private function customEventHandler(e:CustomEvent):void{
  trace(e);
  // without: [Event type="notify" bubbles=false cancelable=true eventPhase=2]
  // with:      [CustomEvent type="notify" data=[object Object] bubbles=false cancelable=true eventPhase=2]
}


// CustomEvent class:
package whatever.events {
    import flash.events.Event;

    public class CustomEvent extends Event {
       
        public static const NOTIFY:String = "notify";
        private var _data:*;
           
        public function CustomEvent(type:String, data:*=null, bubbles:Boolean=false, cancelable:Boolean=false){
            super(type, bubbles, cancelable);
            _data = data;
        }
        override public function clone():Event {
            return new CustomEvent(type, data, bubbles, cancelable);
        }
        override public function toString():String {
            return formatToString("CustomEvent", "data", "type", "bubbles", "eventPhase");
        }
        public function get data():*{
            return _data;
        }
       
    }
}


Thanks and keep up the good work :)
Jakob E


Top Expert 2009

Author

Commented:
Thanks for your feedback Jakob - much appreciated by all of us I'm sure.
When I first started with AS3 I couldn't figure out how to achieve this and eventually arrived at this solution which worked well for me thus far.  I should have mentioned it's how I do it but not necessarily the best way. Usually in the posts I do that but I was repeating myself so many times that I ended up doing this article.


1. explain #1 to me please
2. the get/set option sounds familiar from my Java days. My OOP knowledge and experience is limited.
3. making data null optional would make this much more generic thus better I agree.
4. why?explain.

Commented:

Hi Blue-Genie,

The reason why I like the whatever.events namespace structure
is that it matches the one used by flash - making it easier to remember.

import flash.events.Event
import whatever.events.CustomEvent


About the clone and toString overrides:

Event.clone() is used when re-dispatching an event (dispatchEvent(e)). If you don't add
all the properties then the properties of the re-dispatched event won't have the right values
when listeners handle the re-dispatched event. In our case data will be lost.  

An example:
// Add two listeners:
stage.addEventListener(CustomEvent.NOTIFY,firstDispatchHandler,false,0,true)
button.addEventListener(CustomEvent.NOTIFY,secondDispatchHandler,false,0,true)

// Dispatch the CustomEvent on the first                           
stage.dispatchEvent(new CustomEvent(CustomEvent.NOTIFY,{name:"John Doe"}))

private function firstDispatchHandler(e:CustomEvent):void{
    trace("First: "+e.data.name) // traces "John Doe"
    // Re-dispatch event to the second listener
    dispatchEvent(e)
}

private function secondDispatchHandler(e:CustomEvent):void{
    trace("Second: "e.data.name)
    // Without the clone override you'll get an error:
    // TypeError: Error #1034: Type Coercion failed: cannot convert
    // flash.events::Event@54122a01 to whatever.events.CustomEvent.
}



Event.toString() is not required but I find it useful when unsure about what properties is
passed thru the event.

If you don't override Event.toString() tracing your CustomEvent will show:
[Event type="notify" bubbles=false cancelable=true eventPhase=2]

When overriding you'll get this:  
[CustomEvent type="notify" data=[object Object] bubbles=false cancelable=true eventPhase=2]
Now we know that the event is a CustomEvent with a data property  (in this case an object).
 
Tracing events becomes even more useful when dealing with more "advanced" types - like the MouseEvent:
[MouseEvent type="mouseOver" bubbles=true cancelable=false eventPhase=2 localX=38 localY=41 stageX=265.95
stageY=123 relatedObject=null ctrlKey=false altKey=false shiftKey=false buttonDown=false delta=0]
 

Hope it makes sense :)

Best,
Jakob E
 

 


View More

Have a question about something in this article? You can receive help directly from the article author. Sign up for a free trial to get started.