This question doesn\'t relate only to MouseEvent.CLICK event type but to all event types that already exist in AS3. I read a lot about custom events but until now I couldn\'
Without knowing more about your application, it seems more like you should use the target to pass parameters, or extend MouseEvent. The former would be more in line with common practice, though. So for example, if you exposed an integer public property on your "clip" object (whatever it is):
public class MyClip
{
public var myPublicProperty:int;
public function MyClip() { //... }
}
for (var i:int = 0; i < 10; i++)
{
myClips[i].myPublicProperty = i;
myClips[i].addEventListener(MouseEvent.CLICK, doSomething);
}
... and then, in your event listener, you could retrieve that property using either the target or currentTarget property of the event (probably currentTarget, in your case):
function doSomething(event:MouseEvent):void
{
trace(event.currentTarget.myPublicProperty.toString());
}
That ought to do it! Good luck.
You can accomplish this by getting your handler out of a function that gives the variable closure, like this:
for (var i=0; i<5; i++) {
myClips[i].addEventListener( MouseEvent.CLICK, getHandler(i) );
}
function getHandler(i) {
return function( e:MouseEvent ) {
test(i);
}
}
function test( j ) {
trace("foo "+j);
}
Also, as for why this creates a new closure, you might want to check the explanation in the accepted answer to this similar question.
You really need to extend the event class to create your own event with extra parameters. Placing functions inside the addEventListener (anonymous functions) is a recipe for memory leaks, which is not good. Take a look at the following.
import flash.events.Event;
//custom event class to enable the passing of strings along with the actual event
public class TestEvent extends Event
{
public static const TYPE1 :String = "type1";
public static const TYPE2 :String = "type2";
public static const TYPE3 :String = "type3";
public var parameterText:String;
public function TestEvent (type:String, searchText:String)
{
this.parameterText = searchText;
super(type);
}
}
when you create a new event such as
dispatchEvent(new TestEvent(TestEvent.TYPE1, 'thisIsTheParameterText'))" ;
you can then listen for that event like this
someComponent.addEventListener(TestEvent.TYPE1, listenerFunction, true , 0, true);
and inside the function 'listenerFunction' event.parameterText will contain your parameter.
so inside your myClips component you would fire off the custom event and listen for that event and not the Click event.
private function myCallbackFunction(e:Event, parameter:String):void
{
//voila, here's your parameter
}
private function addArguments(method:Function, additionalArguments:Array):Function
{
return function(event:Event):void {method.apply(null, [event].concat(additionalArguments));}
}
var parameter:String = "A sentence I want to pass along";
movieClip.addEventListener(Event.COMPLETE, addArguments(myCallbackFunction, [parameter] ) );
Take advantage of the dynamic function construction in AS3.
Thanks so much for this usefull tips, this technique is better to understand than classes explanation.
for me I just started new code algorithm using this technique to solve link relation between timers array and viewports array, and update status by change text inside them frequently, by passing ID's with timers events.
like this:
var view:Object=[];
for(var i:uint=0;i<Camera.names.length;i++){
view[i]=getChildByName("Cam"+i);
//_________ Add Text _________
var tf:TextField = new TextField();
tf.autoSize = TextFieldAutoSize.LEFT;
tf.textColor=0xffffff;
view[i].tf=view[i].addChild(tf);
//_________ Add Timer _________
var t:Timer = new Timer(1000);
view[i].timer=t;
view[i].timer.start();
view[i].timer.addEventListener(TimerEvent.TIMER, addArg(i));
}
function addArg(adi:uint):Function {
return function(event:TimerEvent):void {
updatecamstatus(adi);
}
}
function updatecamstatus(vH:uint):void {
with (view[vH]){
tf.text="Cam" + vH + "\n";
tf.appendText("activityLevel: " + videosource.activityLevel + "\n");
tf.appendText("motionLevel: " + videosource.motionLevel + "\n");
}
}
I see your main goal isn't actually to create a custom MouseEvent.CLICK, but to pass a parameter to the function. You don't need to complicatedly create or extend anything. There's a simple and closure-trouble-free way to do it.
Just make your function like this:
function doSomething(index:Number):Function {
return function(e:MouseEvent):void {
// Use "e" and "index" here. They'll be unique for each addEventListener()
trace(index);
}
}
This technique can relate to any AS3 event type you can use addEventListener on.
And now you can add it like this:
var functionsDoSomething:Object;
for (var i:Number = 0; i < 10; i++) {
var someVar:Number = i;
functionsDoSomething[i] = doSomething(someVar);
myClips[i].addEventListener(MouseEvent.CLICK, functionsDoSomething[i]);
}
The doSomething(someVar)
can be used directly on addEventListener()
, but it's better to keep it in a variable because you'll be able to remove it later the same fashion you added it:
for (i = 0; i < 10; i++) {
myClips[i].removeEventListener(MouseEvent.CLICK, functionsDoSomething[i]);
}
The commonly used e.currentTarget.someCustomProperty
works for dynamic objects (i.e. MovieClip), but will let you down at anything else (i.e. Sprite), forcing you to build a whole custom extended object/event for every type.
This solution deals with every "listenable" object and event. And this answer has more details and examples on it.