matteok
matteok

Reputation: 2189

AS3 individual Event listener in for loop

I couldn't find a better title to describe my problem.

I want to achieve this:

for(var i:int = 0; i < 10; i++) {
     var mc:MovieClip = new MovieClip();
     mc.addEventLister(MouseEvent.MOUSE_OVER, function() {
        mc.y=-20;
     });
}

My problem is that mc always referrs to the last mc created in the for loop so the first mc created causes the last one to move on mouseover. Maybe I could use something like "this" or "self"...

Any suggestions?

Upvotes: 0

Views: 1933

Answers (2)

J. Holmes
J. Holmes

Reputation: 18546

There are a bunch of ways to get around this, you could use the event object

for(var i:int = 0; i < 10; i++) {
     var mc:MovieClip = new MovieClip();
     mc.addEventLister(MouseEvent.MOUSE_OVER, function(e) {
        MovieClip(e.currentTarget).y=-20;
     });
}

Or you could use an anonymous closure to create a stable variable scope:

for(var i:int = 0; i < 10; i++) {
     (function(mc:MovieClip):void  {
        mc.addEventLister(MouseEvent.MOUSE_OVER, function(e) {
            mc.y=-20;
        });
     })(new MovieClip());
}

Or a named function to do the same:

function attachListenerTo(mc:MovieClip):void {
    mc.addEventLister(MouseEvent.MOUSE_OVER, function(e) {
        mc.y=-20;
    });
}

for(var i:int = 0; i < 10; i++) {
     attachListenerTo(new MovieClip());
}

Or you could make a subclass of MovieClip and attach the event listener in a bound context:

public dynamic class ChildClass extends MovieClip {
    public function ChildClass() {
        this.addEventListener(MouseEvent.MOUSE_OVER, handleOver);
    }

    private function handleOver(e:MouseEvent):void {
        this.y = -20;
    }
}

// And then

for(var i:uint=0;i<10;i++) {
    var mc:MovieClip = new ChildClass();
}

Edit

Just a quick note as to why your first version fails, ActionScript does not have block scopes (unlike other languages like C#) and uses variable hoisting. This means the line var mc:MovieClip isn't where you think that it is. In fact, there is only one variable called mc and its bound to the functional scope, meaning that through each iteration of the loop you are just reassigning the single variable named mc. Since you are creating an anonymous function as your handler, it too gets bound to the same scope as mc. This is why mc always refers to the last MovieClip from the loop, by the time any of these closures get invoked, it is long after the loop has finished running and mc still points to the last one.

Upvotes: 3

bummzack
bummzack

Reputation: 5875

You want to do something like this:

for(var i:int = 0; i < 10; i++) {
     var mc:MovieClip = new MovieClip();
     mc.addEventLister(MouseEvent.MOUSE_OVER, function(evt:Event) {
        evt.currentTarget.y=-20;
     });
}

Note, that instead of using mc I'm using the currentTarget of the event, which is what we added the event-listener to.

Upvotes: 1

Related Questions