views:

11675

answers:

3

Hello,

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't figure it out how to do what I want to do. I'm going to try to explain, I hope you understand:

Here is a illustration of my situation:

for(var i:Number; i < 10; i++){
    var someVar = i;
     myClips[i].addEventListener(MouseEvent.CLICK, doSomething);
}

function doSomething(e:MouseEvent){ /* */ }

But I want to be able to pass someVar as a parameter to doSomething. So I tried this:

for(var i:Number; i < 10; i++){

    var someVar = i;
    myClips[i].addEventListener(MouseEvent.CLICK, function(){
        doSomething(someVar);
    });
}

function doSomething(index){ trace(index); }

This kind of works but not as I expect. Due to the function closures, when the MouseEvent.CLICK events are actually fired the for loop is already over and someVar is holding the last value, the number 9 in the example. So every click in each movie clip will call doSomething passing 9 as the parameter. And it's not what I want.

I thought that creating a custom event should work, but then I couldn't find a way to fire a custom event when the MouseEvent.CLICK event is fired and pass the parameter to it. Now I don't know if it is the right answer.

What should I do and how?

+2  A: 

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.

fenomas
+1  A: 

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.

Christian Nunciato
I will consider it the right answer (despite the fact that fenomas also provided a right answer) because it showed me a different way to approach my problem. Thanks.
fromvega
+4  A: 

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.

kenneth
Why would anonymous functions be a likely cause of memory leaks, exactly?
fenomas
you have no reference to the function, that combined with the weakReference in the eventListener defaulting to false can if you're not carefull lead to memory leaks. considered bad practise + any flashplayer 9.115 or below has a bug which causes a memory leak for anon funcs.
kenneth
This still doesn't explain how I would fire/dispatch this custom event when a MouseEvent.CLICK event occurs. Am I missing something?
fromvega
Your question is slighty vauge there, you ask about custom events, thats what i've tried to explain. with them you can add whatever parameters you wish. If you wish to fire of custom event when user clicks your component, just use the dispatchEvent code inside the click handler of component.
kenneth