Loading an SWF whose Code is on the Timeline

In our tutorial, Loading External Clips in Flash CS3, we discussed many aspects of loading at runtime external SWFs and controlling them afterwards. In the series of experiments presented in this tutorial, we address the situation when a loaded SWF has references to 'stage'. Such references if not handled properly often lead to the all too common "TypeError: Error #1009: Cannot access a property or method of a null object reference". Below is an example in which an extrnal SWF is loaded:

The loaded SWF occupies the area within the white border.

Download

Download all the 'fla' and 'as' files corresponding to the isues discussed in this tutorial in one zip file.

In all examples, we load an external SWF file into a container file. It is container_1.swf on this page. The external file is called ext_timeline.swf. The ext_timeline.swf file contains references to 'stage'. Namely, it adds a listener to 'stage' that listens to mouse clicks and randomly changes colors of circles when a click occurs. That reference to 'stage' requires extra caution when loading ext_timeline.swf.

Here is the code on the first (and the only) frame of container_1.fla. (For the container SWF, it does not matter if the code in on the timeline or in a Document Class.) We keep comments within the code for greater clarity.

/*
We are creating an instance of the Loader class, 'loader'. 'loader' will load our external swf file.
*/

var loader:Loader=new Loader();

/*
We are creating a variable mcExternal in which we will store the loaded swf. This is tangential to our experiment and illustrates access to methods of the loaded swf from the container swf.
*/

var mcExternal:MovieClip;

/*
The next line is crucial to this experiment. Often an instance of the Loader is added as a child of the MainTimeline upon completion of the load process; that is, in listeners to Event.COMPLETE (or Event.INIT). This works fine unless the loaded swf contains references to 'stage' as ext_timeline.swf does. In order to have access to 'stage', the loaded content must be on the Display List BEFORE any code in it referencing 'stage' is executed.
*/

this.addChild(loader);

loader.load(new URLRequest("ext_timeline.swf"));

/*
To see that it is necessary to add 'loader' as a child before the listener runs, comment out the line 'this.addChild(loader);' above and uncomment 'this.addChild(loader);' in the listener 'swfIn'. A runtime error will be generated.
*/

loader.contentLoaderInfo.addEventListener(Event.COMPLETE,swfIn);

 

function swfIn(e:Event):void {

//trace("Listener in container_1, swfIn, runs.");

//this.addChild(loader);

loader.x=40;

loader.y=40;

loader.contentLoaderInfo.removeEventListener(Event.COMPLETE,swfIn);

mcExternal=loader.content as MovieClip;

mcExternal.renderOrangeCircles();

//mcWait is a movie clip with the message to the user to wait.

mcWait.visible=false;

}

 

To understand the error when 'loader' is added as a child within the listener and not before, one must realize the sequence of events that happen in AVM upon load.

When the loaded SWF is ready to be acccessed, the loaded content is instantiated (by executing the constructor of its Document Class), then the content is added as a child to 'loader' and after that, the timeline code attached to the first frame of the loaded swf (in our case ext_timeline.swf) is executed. All of that happens before the listener 'swfIn' to Event.COMPLETE (or Event.INIT) is executed. Thus, if 'loader' is added as a child in the listener and not before 'load' is called, the loaded movie, ext_timeline.swf, is not on the Display List when its timeline code is executed, and ext_timeline.swf does not have access to 'stage'. An error is then generated. Recall, that whenever a Flash Player runs, there is only one 'stage' object, that of the MainTimeline. In our case, the 'stage' object is that of 'container_1.swf' whose instance is the MainTimeline. 'container_1.swf' is the 'stage owner'. If 'ext_timeline.swf' is opened independently rather that loaded, it has its own 'stage'.

To see that sequence of events uncomment the 'trace' calls in 'swfIn' above and on the first line in ext_timeline.fla. The listener 'swfIn' runs after the timeline code is executed.

Here are relavant portions of the timeline code of ext_timeline.fla. (We skip the portions of the code that draw circles, choose random colors etc.) See ext_timeline.fla in the 'zip' package for complete code.

 

//trace("Timeline code in loaded swf runs.");

//We are defining variables that will hold our circles.

var circle1:Shape=new Shape();

var circle2:Shape=new Shape();

var circle3:Shape=new Shape();

/*
We are calling the functions 'setUpCicles' and 'renderCircles' defined later in the script. 'setUpCircles' creates, adds as children, and positons the circles. 'renderCricles' draws the cicles with fills colors generated randomly. Nothing particularly interesting there.
*/

setUpCircles();

renderCircles();

 

/*
What follows is the portion of the code crucial to this experiment as it involves 'stage'. When this swf is loaded into a container_1.swf, it does not have access to 'stage' until it becomes a part of the Display List. Every time a Flash Player opens a movie there is only one instance of the Stage class created. The 'stage' object reference below is no longer 'stage' of this swf. It is replaced by 'stage' of the container_1.swf.
*/

stage.addEventListener(MouseEvent.CLICK,whenClicked);

 

function whenClicked(e:MouseEvent):void {

renderCircles();

}

 

function setUpCircles():void {

...........................

}

 

/*
'renderCircles' draws the cicles with fills colors generated randomly.
*/

function renderCircles():void {

...........................

}

/*
The next functions draws all circles in orange. We use it to demonstrate access from a container swf to a loaded swf. This is tangential to our experiment.
*/

function renderOrangeCircles():void {

...........................

}

In our ext_timeline.swf the Document Class is not specified. In that case, Flash generates a Document Class automatically. Timeline functions and variables become instance methods and properties of the Document Class.

Instantiating of a loaded swf happens before it is added as a child of 'loader'. Beacause of that in the case when a Document Class is specified, additional issues with 'stage' references arise. We will look at them in our next example, container_2.swf, ext_docclass.swf.

One might think that if the loaded SWF does not use any timeline code and all code resides in an external Document Class the situation is easier to handle. Quite to the contrary. There are more pitfalls if a Document Class for the loaded SWF is used. If a reference to 'stage' appears in the Document Class's constructor, additional steps need to be taken to avoid 1009 error. Of course, the constructor is executed BEFORE the instance of the loaded SWF is added as a child of 'loader'. We discuss the Document Class scenario and how to fix the problem on the next page.

Back to Intermediate Tutorials              Back to Flash and Math Home

We welcome your comments, suggestions, and contributions. Click the Contact Us link below and email one of us.

Adobe®, Flash®, ActionScript®, Flex® are registered trademarks of Adobe Systems Incorporated.