Flex

After creationComplete a Flex component’s stage property is… what? null?

When creating a custom Flex component, it may be desirable to access the stage when initializing the component. However, as stated in the documentation, the stage property of a DisplayObject only becomes accessible (that is, does not appear as null) when the display object has been added to the display list. It would seem intuitive then that the stage property should have a value when the added or the more Flex-specific UIComponent‘s creationComplete event has fired. However, the stage property only acquires a value after the display object has been added to the stage’s display list, not just any display list. For example, when the component is added to its parent’s display list the added event is triggered, but the stage property would still be null as the parent had yet to be added to the stage’s display list.

Thankfully buried somewhere in Flex’s vast API there is an event for every need, or one would hope. And with the update from Flex 2 to Flex 2.0.1 a new event was added to DisplayObject called addedToStage, which consistently provides a way to run initialization code that depends on the stage, such as references to stage.stageWidth, etc.

Consider the following component, which traces out the firing of certain initialization events:

package com.anselmbradford
{
	import mx.core.UIComponent;
	import flash.events.Event;
	import mx.events.FlexEvent;
	import mx.core.Application;
 
 
	public class Component extends UIComponent 
	{		
		public function Component() 
		{
			this.addEventListener( Event.ADDED , addedHandler );			
			this.addEventListener( Event.ADDED_TO_STAGE , addedToStageHandler );
			this.addEventListener( FlexEvent.CREATION_COMPLETE , creationCompleteHandler );			
			Application.application.addEventListener( FlexEvent.APPLICATION_COMPLETE , applicationCompleteHandler );
		}
 
		private function addedHandler( event:Event ) : void
		{
			trace( this , "addedHandler called" , stage );
		}
 
		private function addedToStageHandler( event:Event ) : void
		{
			trace( this , "addedToStageHandler called" , stage );
		}
 
		private function creationCompleteHandler( event:FlexEvent ) : void
		{
			trace( this , "creationCompleteHandler called" , stage );
		}
 
		private function applicationCompleteHandler( event:Event ) : void
		{
			trace( this , "applicationCompleteHandler called" , stage );
		}
 
	}
}

A really nice thing about Flex is that this component could either be instantiated via MXML or ActionScript syntax, since at compile time it all becomes ActionScript anyway. If the position of this component within the layout is important, MXML would be the preferred method.

Instantiating the component with MXML:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:ab="com.anselmbradford.*"
>
     <ab:Component/>
</mx:Application>

Instantiating the component with ActionScript:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml"
applicationComplete="init()"
>
      <mx:Script>
        <![CDATA[
 
            import com.anselmbradford.Component;
 
            private function init() : void
            {
            	this.addChild( new Component() );
            }
 
        ]]>
      </mx:Script>
</mx:Application>

Now take a look at the difference in how the same component’s events are triggering by instantiating the component in MXML versus ActionScript:

Output via MXML instantiation:

Main0.Component4 addedHandler called null
Main0.Component4 creationCompleteHandler called null
Main0.Component4 addedToStageHandler called [object Stage]
Main0.Component4 applicationCompleteHandler called [object Stage]

Output via ActionScript instantiation:

Main0.Component7 addedHandler called [object Stage]
Main0.Component7 addedToStageHandler called [object Stage]
Main0.Component7 creationCompleteHandler called [object Stage]

You’ll notice the only event with a consistently initialized stage property across these two methods of instantiating the component is, not surprisingly, the addedToStage event. The applicationComplete event does not even fire in the ActionScript instantiation example, because the instantiation occurred within the handler for the applicationComplete event of the main application MXML file, and therefore the component was constructed after that event had already fired.

The bottom line: listen for the addedToStage event if you want to be sure the stage property has a value when it is accessed.