Event handler scope

The scope, or context, of variables and commands that you declare and execute within an event handler depends on the type of event handler you use: event handlers or event listeners, or on() and onClipEvent() handlers. If you're defining an event handler in a new ActionScript class, the scope also depends on how you define the event handler. This section contains both ActionScript 1.0 and ActionScript 2.0 examples.

ActionScript 1.0 examples Functions assigned to event handler methods and event listeners (as with all ActionScript functions that you write) define a local variable scope, but on() and onClipEvent() handlers do not.

For example, consider the following two event handlers. The first is an onPress event handler associated with a movie clip named clip_mc. The second is an on() handler attached to the same movie clip instance.

// Attached to clip_mc's parent clip timeline:
clip_mc.onPress = function () {
    var shoeColor; // local function variable
    shoeColor = "blue";
}
// on() handler attached to clip_mc:
on (press) {
    var shoeColor; // no local variable scope
    shoeColor = "blue";
}    

Although both event handlers contain the same code, they have different results. In the first case, the color variable is local to the function defined for onPress. In the second case, because the on() handler doesn't define a local variable scope, the variable is defined in the scope of the timeline of the clip_mc movie clip.

For on() event handlers attached to buttons, rather than to movie clips, variables (as well as function and method calls) are invoked in the scope of the timeline that contains the button instance.

For instance, the following on() event handler produces different results that depend on whether it's attached to a button or movie clip object. In the first case, the play() function call starts the playhead of the timeline that contains the button; in the second case, the play() function call starts the timeline of the movie clip to which the handler is attached.

// Attached to button.
on (press) {
    play(); // Plays parent timeline.
}
// Attached to movie clip.
on (press) {
    play(); // Plays movie clip's timeline.
}

When attached to a button object, the play() function applies to the timeline that contains the button--that is, the button's parent timeline. But when the on(press) handler is attached to a movie clip object, the play() function call applies to the movie clip that bears the handler. If you attach the following code to a movie clip, it plays the parent timeline:

// Attached to movie clip.
on (press) {
    _parent.play(); // Plays parent timeline.
}

Within an event handler or event listener definition, the same play() function applies to the timeline that contains the function definition. For example, suppose you declare the following my_mc.onPress event handler method on the timeline that contains the my_mc movie clip instance:

// Function defined on a timeline 
my_mc.onPress = function () {
    play(); // plays timeline that it is defined on.
};

To play the movie clip that defines the onPress event handler, refer explicitly to that clip using the this keyword, as follows:

// Function defined on root timeline
my_mc.onPress = function () {
    this.play(); // plays timeline of my_mc clip.
};

However, the same code placed on the root timeline for a button instance would instead play the root timeline:

my_btn.onPress = function () {
    this.play(); // plays root timeline
};

For more information about the scope of the this keyword in event handlers, see Scope of the this keyword.

ActionScript 2.0 example The following TextLoader class is used to load a text file and display some text after it successfully loads the file.

// TextLoader.as
class TextLoader {
    private var params_lv:LoadVars;
    public function TextLoader() {
        params_lv = new LoadVars();
        params_lv.onLoad = onLoadVarsDone;
        params_lv.load("http://www.helpexamples.com/flash/params.txt");
    }
    private function onLoadVarsDone(success:Boolean):Void {
        _level0.createTextField("my_txt", 999, 0, 0, 100, 20);
        _level0.my_txt.autoSize = "left";
        _level0.my_txt.text = params_lv.monthNames; // undefined
    }
}

This code cannot work correctly because there is a problem involving scope with the event handlers, and what this refers to is confused between the onLoad event handler and the class. The behavior that you might expect in this example is that the onLoadVarsDone() method will be invoked in the scope of the TextLoader object; but it is invoked in the scope of the LoadVars object because the method was extracted from the TextLoader object and grafted onto the LoadVars object. The LoadVars object then invokes the this.onLoad event handler when the text file is successfully loaded, and the onLoadVarsDone() function is invoked with this set to LoadVars, not TextLoader. The params_lv object resides in the this scope when it is invoked, even though the onLoadVarsDone() function relies on the params_lv object by reference. Therefore, the onLoadVarsDone() function is expecting a params_lv.params_lv instance that does not exist.

To correctly invoke the onLoadVarsDone() method in the scope of the TextLoader object, you can use the following strategy: use a function literal to create an anonymous function that calls the desired function. The owner object is still visible in the scope of the anonymous function, so it can be used to find the calling TextLoader object.

// TextLoader.as
class TextLoader {
    private var params_lv:LoadVars;
    public function TextLoader() {
        params_lv = new LoadVars();
        var owner:TextLoader = this;
        params_lv.onLoad = function (success:Boolean):Void {
            owner.onLoadVarsDone(success);
        }
        params_lv.load("http://www.helpexamples.com/flash/params.txt");
    }
    private function onLoadVarsDone(success:Boolean):Void {
        _level0.createTextField("my_txt", 999, 0, 0, 100, 20);
        _level0.my_txt.autoSize = "left";
        _level0.my_txt.text = params_lv.monthNames; // January,February,March,...
    }
}