Creating and managing container children at run time

You typically use MXML to lay out the user interface of your application, and use ActionScript for event handling and run-time control of the application. You can also use ActionScript to create component instances at run time. For example, you could use MXML to define an empty Accordion container and use ActionScript to add panels to the container in response to user actions.

About the display list and container children

Flash Player maintains a tree of visible (or potentially visible) objects that make up your application. The root of the tree is the Spark Application or MX Application object, and child containers and components are branches and leaf nodes of the tree. That tree is known as the display list. When you add child components to a container or remove child components from a container, you are adding and removing them from the display list. You can also change their relative positions by changing their positions in the display list.

Although the display list is a tree rooted at the top of the application, when you manipulate a container’s children by ’s methods and properties, you only access the container’s direct children. Treat the container’s children as items in a list, where the first child has an index of 0.

Using the container API for managing container children

Spark Group and SkinnableContainer containers, and all MX containers, provide properties and methods that you use to manage the container’s children. Because the Spark Group and SkinnableContainer containers can hold many types of children, the methods that you use to manipulate its children refer to the children by a generic name of element.
Note: This section does not apply to the Spark DataGroup and Spark SkinnableDataContainer. Those containers use a data provider to define their children. You manage the children of those containers in the same way that you manage any data provider control. For more information, see Data providers and collections and The Spark DataGroup and Spark SkinnableDataContainer containers.
The following table shows these properties and methods:

Spark container

MX container

Description

numElements

numChildren

Number of children in the container.

addElement()

addChild()

Adds a child to the container as the last child.

addElementAt()

addChildAt()

Add a child at a specific index in the container.

 

getChildren()

Returns an Array containing all children.

getElementAt()

getChildAt()

Return a child at the specified index.

 

getChildByName()

Return a child with the specified id.

getElementIndex()

getChildIndex()

Returns the index of a child.

removeAllElements()

removeAllChildren()

Removes all container children.

removeElement()

removeChild()

Remove the first child.

removeElementAt()

removeChildAt()

Remove the child at the specified index

setElementIndex()

setChildIndex()

Set the index of a child.

swapElements()

swapChildren()

Swap the indexes of two children

swapElementsAt()

swapChildrenAt()

Swap the indexes of two children.

Note: Make sure that you use the correct method for your type of container, either Spark or MX. Using the wrong method can cause unexpected results.

Obtaining the number of child components in a container or application

Use the numElements or numChildren property to obtain a count of the number of direct child components that the container has in the display list. The following application gets the number of children in the application and a Group container. The Group control has five label controls, and therefore has five children. The Application container has the Group and Button controls as its children, and therefore has two children.

<?xml version="1.0"?>
<!-- containers\intro\VBoxNumChildren.mxml -->
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:mx="library://ns.adobe.com/flex/mx" 
    xmlns:s="library://ns.adobe.com/flex/spark">
    <s:layout>
        <s:VerticalLayout/>
    </s:layout>
    
    <fx:Script>
      <![CDATA[
            // Import the Alert class.
            import mx.controls.Alert;
    
            public function calculateChildren():void {
                var myText:String = new String();
                myText="The Group container has " + 
                    myGroup.numElements + " children.";
                myText+="\nThe application has " + 
                    numElements + " children.";
                Alert.show(myText);
            }        
        ]]>
    </fx:Script>

    <s:VGroup id="myGroup">
        <s:Label text="This is label 1."/>
        <s:Label text="This is label 2."/>
        <s:Label text="This is label 3."/>
        <s:Label text="This is label 4."/>
        <s:Label text="This is label 5."/>
    </s:VGroup>  
    
    <s:Button label="Show Children" click="calculateChildren();"/>
</s:Application>

The executing SWF file for the previous example is shown below:

In the main MXML application file, the file that contains the <s:Application> tag, the current scope is always the Application object. Therefore, the reference to the numElements property without an object prefix refers to the numElements property of the Application object. For more information on accessing the root application, see About scope.

Accessing display-only children

The MX Container class defines the rawChildren property that contains the full display list of all the children of a container. This list includes all the container’s children, plus the DisplayObjects that implement the container’s chrome (display elements), such as its border and the background image.

The numChildren property and accessor methods let you count and access only child components. However, the container might contain style elements and skins, such as the border and background. The container’s rawChildren property lets you access all children of a container, including the component “content children” and the skin and style “display children.” The object returned by the rawChildren property implements the IChildList interface. You then use methods and properties of this interface, such as getChildAt(), to access and manipulate all the container’s children.

Creating and removing components at run time

To create a component instance at run time, you define it, set any properties, and then add it as a child of a parent container by calling the addElement() or addChild() method on the parent container.

The addElement() method has the following signature:

addElement(element:IVisualElement):IVisualElement

The element argument specifies the component to add to the container.

The addChild() method has the following signature:

addChild(child:DisplayObject):DisplayObject 

The child argument specifies the component to add to the container.

Note: Although the child argument of the addChild() method is specified as type DisplayObject, the argument must implement the IUIComponent interface to be added as a child of a container. All Flex components implement this interface.

For example, the following application creates a Group container with an Button control called myButton:

<?xml version="1.0"?>
<!-- containers\intro\ContainerAddChild.mxml -->
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:mx="library://ns.adobe.com/flex/mx" 
    xmlns:s="library://ns.adobe.com/flex/spark">

    <fx:Script>
        <![CDATA[
            import spark.components.Button;

            public function addButton():void {
                var myButton:Button = new Button();
                myButton.label = "New Button";
                myGroup.addElement(myButton);
            }
        ]]>
    </fx:Script> 

    <s:Group id="myGroup" initialize="addButton();"/>
</s:Application>

The executing SWF file for the previous example is shown below:

This example creates the control when the application is loaded rather than in response to any user action. However, you could add a new button when the user presses an existing button, as the following example shows:

<?xml version="1.0"?>
<!-- containers\intro\ContainerAddChild2.mxml -->
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:mx="library://ns.adobe.com/flex/mx" 
    xmlns:s="library://ns.adobe.com/flex/spark">

    <fx:Script>
        <![CDATA[
            import spark.components.Button;

            public function addButton():void {
                var myButton:Button = new Button();
                myButton.label = "New Button";
                myGroup.addElement(myButton);
            }
        ]]> 
    </fx:Script>

    <s:HGroup id="myGroup">
        <s:Button label="Add Button" click="addButton();"/>
    </s:HGroup>
</s:Application>

The executing SWF file for the previous example is shown below:

You use the removeElement() or removeChild() method to remove a control from a container. If the child is no longer referenced anywhere else in your application after the call, it gets destroyed by a garbage collection process. The following example removes a button from the application when the user presses it:

<?xml version="1.0"?>
<!-- containers\intro\ContainerRemoveChild.mxml -->
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:mx="library://ns.adobe.com/flex/mx" 
    xmlns:s="library://ns.adobe.com/flex/spark">
    <s:layout>
        <s:VerticalLayout/>
    </s:layout> 

    <fx:Script>
        <![CDATA[
            public function removeButton():void {
                myGroup.removeElement(myButton);
            }
            
            private function resetApp():void {
                if (myGroup.numElements == 0) {
                    myGroup.addElement(myButton); 
                }
            }
        ]]> 
    </fx:Script>

    <s:Group id="myGroup">
        <s:Button id="myButton" 
            label="Remove Me" 
            click="removeButton();"/>
    </s:Group>
    <s:Button label="Reset" click="resetApp();"/>
</s:Application>

The executing SWF file for the previous example is shown below:

For additional methods that you can use with container children, see the ActionScript 3.0 Reference for the Adobe Flash Platform.

Example: Creating and removing a child of a container

The following example uses MXML to define a container that contains two Button controls. You use one Button control to add an CheckBox control to the container, and one Button control to delete it.

<?xml version="1.0"?>
<!-- containers\intro\ContainerComponentsExample.mxml -->
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:mx="library://ns.adobe.com/flex/mx" 
    xmlns:s="library://ns.adobe.com/flex/spark">
    
    <fx:Script>
      <![CDATA[

        // Import the CheckBox class.
        import spark.components.CheckBox;

        // Define a variable to hold the new CheckBox control.
        private var myCheckBox:CheckBox;
        
        // Define a variable to track if the CheckBox control 
        // is in the display list.
        private var checkBoxDisplayed:Boolean = false;
        
        public function addCB():void {
            // Make sure the check box isn't being displayed.
            if(checkBoxDisplayed==false){
                // Create the check box if it does not exist.
                if (!myCheckBox) {
                    myCheckBox = new CheckBox();
                    myCheckBox.label = "New CheckBox";
                }

                // Add the check box.
                myGroup.addElement(myCheckBox);
                checkBoxDisplayed=true;
            }
        }
    
        public function delCB():void {
            // Make sure a CheckBox control exists.
            if(checkBoxDisplayed){
                myGroup.removeElement(myCheckBox);
                checkBoxDisplayed=false;
            }
        }        
      ]]>
    </fx:Script>

    <s:VGroup id="myGroup">
        <s:Button label="Add CheckBox" 
            click="addCB();"/>          
        <s:Button label="Remove CheckBox" 
            click="delCB();"/>
    </s:VGroup>
</s:Application>

The executing SWF file for the previous example is shown below:

Example: Creating and removing children of an Accordion container

The following example adds panels to and removes them from an MX Accordion container. The Accordion container initially contains one panel. Each time you select the Add HBox button, it adds a new HBox container to the Accordion container.
Note: MX navigators can only take MX containers and the Spark NavigatorContent container as children. You cannot use other Spark containers as direct children of a navigator container. Instead, wrap the Spark container in an MX container on in a Spark NavigatorContent container when adding the Spark container to a navigator.
<?xml version="1.0"?>
<!-- containers\intro\ContainerComponentsExample2.mxml -->
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:mx="library://ns.adobe.com/flex/mx" 
    xmlns:s="library://ns.adobe.com/flex/spark">

    <fx:Script>
        <![CDATA[

            /* Import HBox class. */
            import mx.containers.HBox;
    
            /* Array of created containers. */
            private var myHBoxes:Array = [];

            public function addHBox():void {
                /* Create new HBox container. */
                var newHBox:HBox = new HBox();
                newHBox.label="Label: " + String(myHBoxes.length);

                /* Add it to the Accordion container, and to the 
                   Array of HBox containers. */
                myHBoxes.push(myAcc.addChild(newHBox));
            }

            public function delHBox():void {
                /* If there is at least one HBox container in the Array, 
                   remove it. */
                if (myHBoxes.length>= 1) {
                    myAcc.removeChild(myHBoxes.pop());
                }
            }
      ]]>
    </fx:Script>

    <s:VGroup>
        <mx:Accordion id="myAcc" height="150" width="150">
            <mx:HBox/>
        </mx:Accordion>
        
        <s:Button label="Add HBox" click="addHBox();"/>
        <s:Button label="Remove HBox" click="delHBox();"/>       
    </s:VGroup>
</s:Application>

The executing SWF file for the previous example is shown below:

Controlling child order

You can control the order of children by adding them in a specific order. You can also control them as follows:

  • By using the addElementAt() or addChildAt() method to specify where among the component’s children to add a child

    Note: As with the addChild() method, although the child argument of the addChildAt() method is specified as type DisplayObject, the argument must implement the IUIComponent interface to be added as a child of a container. All Flex components implement this interface.
  • By using the setElementAt() or setChildIndex() method to specify the location of a specific child among a component’s children in the display list

The following example modifies the previous example. It uses the addElementAt() method to add the CheckBox control as the first child (index 0) of the VGroup. It also has a Reorder children button that uses the setChildIndex() method to move a CheckBox control down the display list until it is the last child in the VGroup container.

<?xml version="1.0"?>
<!-- containers\intro\ContainerComponentsReorder.mxml -->
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:mx="library://ns.adobe.com/flex/mx" 
    xmlns:s="library://ns.adobe.com/flex/spark">
     
    <fx:Script>
      <![CDATA[

        // Import the CheckBox and Alert classes.
        import spark.components.CheckBox;
        import mx.controls.Alert;

        // Define a variable to hold the new CheckBox control.
        private var myCheckBox:CheckBox;
        
        // Define a variable to track if the CheckBox control 
        // is in the display list.
        private var checkBoxDisplayed:Boolean = false;
        
        public function addCB():void {  
            // Make sure the check box isn't being displayed.
            if(checkBoxDisplayed==false){
                // Create the check box if it does not exist.
                if (!myCheckBox) {
                    myCheckBox = new CheckBox();
                    myCheckBox.label = "New CheckBox";
                }
                // Add the check box as the first child of the container.
                myGroup.addElementAt(myCheckBox, 0);
                checkBoxDisplayed=true;
            }
        }
    
        public function delCB():void {
            // Make sure a CheckBox control exists.
            if(checkBoxDisplayed){
                myGroup.removeElement(myCheckBox);
                checkBoxDisplayed=false;
            }
        }
        
        public function reorder():void {
        // Make sure a CheckBox control exists.
            if(checkBoxDisplayed==true)
            {
                // Don't try to move the check box past the end 
                // of the children. Because indexes are 0 based, 
                // the last child index is one less
                // than the number of children.
                if (myGroup.getElementIndex(myCheckBox) < myGroup.numElements-1)
                {
                    // Increment the checkBoxIndex variable and use it to 
                    // set the index of the check box among the VBox children. 
                    myGroup.setElementIndex(myCheckBox,
                        myGroup.getElementIndex(myCheckBox) + 1);
                }
            }
            else {
                Alert.show("Add the check box before you can move it");
            }
        }
      ]]>
    </fx:Script>

    <s:VGroup id="myGroup">
        <s:Button label="Add CheckBox" click="addCB();"/>
        <s:Button label="Remove CheckBox" click="delCB();"/>
        <s:Button label="Reorder children" click="reorder();"/>
    </s:VGroup>
</s:Application>

The executing SWF file for the previous example is shown below: