With a foothold firmly established in understanding what you are doing declaratively with MXML and how it relates to the Flex class library, you can start digging for some other really interesting features you might have otherwise overlooked. Now look at the View.createChild() method. This method requires:
Because the View class is the base class for almost every container, everything from the Application class to the HBox class to the Canvas class supports this method through inheritance. With this in mind, you can create an entire UI programmatically through ActionScript. In the following code example, you will add a Label, TextInput, and Button component to your application through this dynamic technique to create a simple “Hello World” example.
<?xml version="1.0" encoding="utf-8"?>
<mx:Application initialize="initApp()"
xmlns:mx="http://www.macromedia.com/2003/mxml">
<mx:Script>
<![CDATA[
import mx.controls.Label;
import mx.controls.TextInput;
import mx.controls.Button;
import mx.containers.Panel;
public var btnSubmit:Button = null;
public var txtFirst:TextInput = null;
public function initApp( Void ):Void {
var pnlHello:Panel = null;
var init:Object = null;
init = new Object();
init.verticalAlign = "middle";
init.direction = "horizontal";
init.title = "Hello World";
pnlHello = Panel( createChild( Panel, "pnlHello", init ) );
init = new Object();
init.text = "First name:";
pnlHello.createChild( Label, "lblFirst", init );
init = new Object();
init.text = "Macromedia";
txtFirst = TextInput( pnlHello.createChild( TextInput, "txtFirst", init ) );
init = new Object();
init.label = "Submit";
btnSubmit = Button( pnlHello.createChild( Button, "btnSubmit", init ) );
btnSubmit.addEventListener( "click", this );
}
public function handleEvent( event:Object ):Void {
if( event.type == "click" ) {
if( event.target == btnSubmit ) {
alert( "Hello " + txtFirst.text + "!", "Alert" );
}
}
}
]]>
</mx:Script>
</mx:Application>
There are a few interesting points about this code example:
Here, I have chosen an initApp() method that creates the UI, which is called during the initialize event of the application. For all practical purposes, the end user could drive the creation of the UI. I will talk more about this soon. Notice that I have also declared object variables for the UI components I wish to use outside of the initApp() method.
Once I started creating the UI objects, I used an internal variable of type Object to hold my initialization properties. You may also use the classic ActionScript approach, using brackets (such as {text:”Macromedia”}) inline.
The example may also introduce you to casting in ActionScript which I do to leverage the benefits of strict data typing. By default, View.createChild() actually returns a MovieClip object. This general data type may cause confusion or errors down the road, so while casting isn’t necessarily required, I encourage you to use it for code maintainability. Also notice that when creating the Label object, I ignore the return altogether. Since I won’t programmatically manipulate the Label object during the application, there’s no need to store a named reference.
Lastly, notice how event handling differs when building dynamic UIs through ActionScript. In this example, the submit button must raise its click event so that the application can display an alert dialog box. Rather than use the init object, you leverage the UIEventDispatcher.addEventListener() method. When triggered, the EventDispatcher calls an handleEvent() method, which you must implement.
The handleEvent() method takes an object as an argument which you can use to understand which component raised the event. The object argument has two properties: one specifies the event type and the other the event target (the component that fired the event). Since all components used in this programmatic fashion might call the handleEvent() method, you need to examine the type and target properties to isolate events and take appropriate action.
Tip: When implementing the Model View Controller (MVC) composite pattern, it can be useful to leverage the event object by adding additional data properties. For example, if your MXML component contains a <mx:DataGrid> that triggers a change event, you will likely pass the selectedItem from the grid to any listeners. You might be inclined to have the component parent access the property directly, but this creates a tight coupling between UI elements. It is cleaner to add the selectedItem to the event object and let the parent leverage that property.
One key flaw to note in this example: It requires far more code and can be substantially less maintainable. Clearly, you do not want to leverage this technique for generic UI requirements, but it can prove exceptionally useful in a number of scenarios. Generally, you can use this method to add components to your application at runtime when you might otherwise not know how many you will need.
An example where this type of dynamic creation is useful might be a product comparison matrix. For instance, let's say that your application lists products that are similar in nature. You would like to create functionality so that the user can drag products to an area on the screen that presents more information about those products for side-by-side comparison. Once the user has dropped a product on the comparison area, you can now create an instance of the special comparison view (MXML component) and pass it the required data.
There is also the opposite method, View.destroyChild(), that you can use to remove controls from the user interface.