In a recent project I was forced to dynamically generating UI Elements in flex from Strings. This is typically done using getDefinitionByName() as shown bellow. Although this works, in my app I never really know what the string is, nor do I know what the Class is named or where it is located. This becomes an issue since you must make reference to the Class somewhere in your code before it is available to the Flex framework.
This example shows the typical use of getDefinitionByName() with out any external SWC. Notice the imports and class references on the top of the Script block.
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 | <?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" xmlns:controls="com.controls.*"> <mx:Script> <![CDATA[ import flash.utils.getDefinitionByName; //You must import the classes and instantiate them import com.controls.TestControlA;TestControlA; import com.controls.TestControlB;TestControlB; private function loadTestClass(name:String):void { var ClassReference:Class = getDefinitionByName(name) as Class; var s:DisplayObject = (new ClassReference() as DisplayObject) testContainer.addChild(s); } ]]> </mx:Script> <mx:VBox id="testContainer" /> <mx:HBox id="buttonBar"> <!--You have to place the entire package location in the string--> <mx:Button label="Test A" click="loadTestClass('com.controls.TestControlA')" /> <mx:Button label="Test B" click="loadTestClass('com.controls.TestControlB')" /> </mx:HBox> </mx:Application> |
This won’t work since I need to make a reference to Classes that I won’t know the names of till run-time. My first step was to move a control into an external SWC, however I still am forced to make reference to the class so it becomes available, or I will get an error. This is a no go.
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 | <?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" xmlns:controls="com.controls.*"> <mx:Script> <![CDATA[ import flash.utils.getDefinitionByName; //You must import the classes and instantiate them import com.controls.TestControlA;TestControlA; import com.controls.TestControlB;TestControlB; import com.controls.TestControlB;TestControlC; //Located in an External SWC private function loadTestClass(name:String):void { var ClassReference:Class = getDefinitionByName(name) as Class; var s:DisplayObject = (new ClassReference() as DisplayObject) testContainer.addChild(s); } ]]> </mx:Script> <mx:VBox id="testContainer" /> <mx:HBox id="buttonBar" > <!--You have to place the entire package location in the string--> <mx:Button label="Test A" click="loadTestClass('com.controls.TestControlA')" /> <mx:Button label="Test B" click="loadTestClass('com.controls.TestControlB')" /> <mx:Button label="Test C" click="loadTestClass('com.controls.TestControlC')" /> </mx:HBox> </mx:Application> |
The solution was actually pretty simple. If Flex is asking for a reference then why not just give it one. In the Library Project i create an additional Module file which i then loaded into my Shell application. Once the module is loaded then getDefinitionByName() works!
Shell Flex Application
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 | <?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" xmlns:controls="com.controls.*"> <mx:Script> <![CDATA[ import flash.utils.getDefinitionByName; import com.controls.TestControlA;TestControlA; import com.controls.TestControlB;TestControlB; import com.controls.TestControlC;TestControlC;//Located in an External SWC //NO REFEREANCE TO TestControlD private function loadTestClass(name:String):void { var ClassReference:Class = getDefinitionByName(name) as Class; var s:DisplayObject = (new ClassReference() as DisplayObject) testContainer.addChild(s); } ]]> </mx:Script> <controls:ExternalClassModule creationComplete="buttonBar.visible=true" /> <mx:VBox id="testContainer" /> <mx:HBox id="buttonBar" visible="false"> <mx:Button label="Test A" click="loadTestClass('com.controls.TestControlA')" /> <mx:Button label="Test B" click="loadTestClass('com.controls.TestControlB')" /> <mx:Button label="Test C" click="loadTestClass('com.controls.TestControlC')" /> <mx:Button label="Test D" click="loadTestClass('com.controls.TestControlD')" /> </mx:HBox> </mx:Application> |
Module in External Library Project
1 2 3 4 5 6 7 8 | <?xml version="1.0" encoding="utf-8"?> <mx:Module xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"> <mx:Script> <![CDATA[ import com.controls.TestControlD;TestControlD; ]]> </mx:Script> </mx:Module> |
Popularity: 7% [?]
actionscript, AS3, Flex










Really… your just side-stepping the AS import with a MXML reference (see: xmlns:controls=”com.controls.*”). This is possible though…
You’ll need to mark your dynamic components a Modules in the IDE – which compiles them to a .swf file. You can then load them with your preferred loader… and instantiate them dynamically without imports or MXML references.
// where object is the .swf module you just loaded…
var className:String = getQualifiedClassName(object);
// instantiate the object
var clazz:Class = getDefinitionByName(className) as Class;
var target:Object = new ClassFactory(clazz).newInstance();
…addChild( target as DisplayObject ). Done.
I originally tried doing it that way, but must have done something wrong in processes. I am going to revisit this ASAP since your method is much less of a work around then mine.