Adding Multiple Children in a Flex State

Many times I’ve had to add multiple children in a Flex state. Take the following simple example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical">
	<mx:Label id="topLabel" text="Top" />
	<mx:Button label="showChildren" click="currentState='children';" />
	<mx:states>
		<mx:State name="children">
			<mx:AddChild relativeTo="{topLabel}" position="after">
				<mx:Label text="third" />
			</mx:AddChild>
			<mx:AddChild relativeTo="{topLabel}" position="after">
				<mx:Label text="second" />
			</mx:AddChild>
			<mx:AddChild relativeTo="{topLabel}" position="after">
				<mx:Label text="first" />
			</mx:AddChild>
		</mx:State>
	</mx:states>
</mx:Application>

In this example I’m adding three labels in the “children” state. Notice that I have to do three seperate AddChild calls and I have to do the in reverse order in order to get them in the correct order in the display.

To make this a little easier, I create a custom class (AddChildren) that acts as a composite for adding multiple children. The class implements IOverride and grabs the children as an array and creates a seperate AddChild action for each one.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:states="com.dannypatterson.states.*" layout="vertical">
	<mx:Label id="topLabel" text="Top" />
	<mx:Button label="showChildren" click="currentState='children';" />
	<mx:states>
		<mx:State name="children">
			<states:AddChildren relativeTo="{topLabel}" position="after">
				<mx:Label text="first" />
				<mx:Label text="second" />
				<mx:Label text="third" />
			</states:AddChildren>
		</mx:State>
	</mx:states>
</mx:Application>

Here is the AddChildren class. I also attached it below for easy download:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
package com.dannypatterson.states {
 
	import mx.core.UIComponent;
	import mx.states.AddChild;
	import mx.states.IOverride;
 
	// This sets the children property as the property that should get the sub declarations.
	[DefaultProperty("children")]
 
	/**
	 * Composite version of AddChild for use within states.
	 *
	 * <mx:State name="children">
	 * 		<states:AddChildren relativeTo="{topLabel}" position="after">
	 * 			<mx:Label text="first" />
	 * 			<mx:Label text="second" />
	 * 			<mx:Label text="third" />
	 * 		</states:AddChildren>
	 * 	</mx:State>
	 */
	public class AddChildren implements IOverride {
 
		private var childActions:Array;
		private var _relativeTo:UIComponent;
		private var _position:String;
		private var _creationPolicy:String;
 
		/**
		 * @see mx.states.AddChild#relativeTo
		 */
		public function set relativeTo(_relativeTo:UIComponent):void {
			this._relativeTo = _relativeTo;
			for(var i:int = 0; i < childActions.length; i++) {
 				AddChild(childActions[i]).relativeTo = _relativeTo;
 			}
		}
 
		/**
		 * @see mx.states.AddChild#position
		 */
		public function set position(_position:String):void {
			this._position = _position;
			for(var i:int = 0; i < childActions.length; i++) {
 				AddChild(childActions[i]).position = _position;
 			}
		}
 
		/**
		 * @see mx.states.AddChild#creationPolicy
		 */
		public function set creationPolicy(_creationPolicy:String):void {
			this._creationPolicy = _creationPolicy;
			for(var i:int = 0; i < childActions.length; i++) {
 				AddChild(childActions[i]).creationPolicy = _creationPolicy;
 			}
		}
 
		/**
		 * This is set as the default property for this component, so the children are passed in through this property.
		 * This is typed so that all children must be instances of UIComponent.
		 */
		[ArrayElementType("mx.core.UIComponent")]
 		public function set children(_children:Array):void {
 			for(var i:int = 0; i < _children.length; i++) {
 				childActions[i] = new AddChild(_relativeTo, _children[i], _position);
 				childActions[i].creationPolicy = _creationPolicy;
 			}
 		}
 
		public function AddChildren() {
			childActions = new Array();
		}
 
		/**
		 * This just defers the call to the sub AddChild actions.
		 *
		 * @see mx.states.IOverride#initialize
		 */
		public function initialize():void {
			for(var i:int = 0; i < childActions.length; i++) {
 				AddChild(childActions[i]).initialize();
 			}
		}
 
		/**
		 * This just defers the call to the sub AddChild actions.
		 * We have to loop through the children backwards to make sure they are added in the correct order.
		 *
		 * @see mx.states.IOverride#apply
		 */
		public function apply(parent:UIComponent):void {
			for(var i:int = childActions.length - 1; i >= 0; i--) {
 				AddChild(childActions[i]).apply(parent);
 			}
		}
 
		/**
		 * This just defers the call to the sub AddChild actions.
		 *
		 * @see mx.states.IOverride#remove
		 */
		public function remove(parent:UIComponent):void {
			for(var i:int = 0; i < childActions.length; i++) {
 				AddChild(childActions[i]).remove(parent);
 			}
		}
 
	}
}

AddChildrenTest1.zip

3 thoughts on “Adding Multiple Children in a Flex State

  1. Don Kerr

    Thanks Danny. This is very helpful.

    I’m trying to figure out how to add multiple children of different component types (label, textarea, image,btn) using an ArrayCollection dataProvider.

    Your example gets me close to it, except in my case, I may not know what the components are to hard code the first, second, third children.

    Just wanted to say thanks. Good stuff!
    Don

    Reply