Dynamic form Generation / Rendering / Validation using XML – in Flex

This example helps in creating a dynamic form, from a XML using actionscript. Dynamic validation has also been done for Textinput and Dropdownlist in this example. Dynamic form Generation in Flex 4.
To create a form on the run, dynamically from a XML. It also does validation dynamically on the fly. Will be helpful to solve many cases where formitems are usually changed on a regular basis. This solution helps in making minor changes to an external XML file rather than making code changes in Flex and hence resulting in a new Bin-release.

Demo

Get Adobe Flash player

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
			   xmlns:s="library://ns.adobe.com/flex/spark" 
			   xmlns:mx="library://ns.adobe.com/flex/mx" 
			   creationComplete="handleCreationComplete()">
 
	<fx:Declarations>
		<fx:XML id="formdata">
			<userinfoform>
				<user>
					<firstname inputtype="TextInput" formlabel="First Name" required="true">true</firstname>
					<lastname inputtype="TextInput" formlabel="Last Name" required="true">true</lastname>
					<nickname inputtype="TextInput" formlabel="Nick Name" required="false">false</nickname>
					<combobox inputtype="ComboBox" formlabel="Gender" required="true">Male,Female</combobox>
					<type inputtype="ComboBox" formlabel="Type" required="false">Book,Cds,Games</type>
					<radioButtonGroup inputtype="RadioButtonGroup" formlabel="Gender" required="false">
						<radiobutton inputtype="RadioButton" formlabel="Gender" required="true">Male</radiobutton>
						<radiobutton inputtype="RadioButton" formlabel="Gender" required="true">Female</radiobutton>
					</radioButtonGroup>	
 
				</user>
			</userinfoform>
		</fx:XML>
	</fx:Declarations>
	<fx:Script>
		<![CDATA[
			import flashx.textLayout.events.SelectionEvent;
 
			import mx.collections.ArrayCollection;
			import mx.containers.FormItem;
			import mx.containers.HBox;
			import mx.containers.VBox;
			import mx.controls.Alert;
			import mx.controls.Label;
			import mx.controls.RadioButton;
			import mx.controls.RadioButtonGroup;
			import mx.controls.TextInput;
			import mx.core.UIComponent;
			import mx.events.ItemClickEvent;
			import mx.events.ValidationResultEvent;
			import mx.rpc.events.FaultEvent;
			import mx.rpc.events.ResultEvent;
			import mx.validators.NumberValidator;
			import mx.validators.StringValidator;
 
			import spark.components.ComboBox;
			import spark.components.DropDownList;
			import spark.components.RadioButton;
			import spark.components.RadioButtonGroup;
			import spark.components.TextArea;
 
			private function handleCreationComplete():void
			{
				//Below line can be used for XML from an external source
				//XMLService.send();
 
				buildForm(new XML(formdata));
			}
 
			private function errorHandler(evt:FaultEvent):void
			{
				Alert.show("Error: " + evt.fault.message);
			}
 
			private function resultHandler(evt:ResultEvent):void
			{				
				buildForm(new XML(evt.result));
			}
 
			private function buildForm(xml:XML):void
			{
				var lst:XMLList = xml.children();
 
				for(var i:int = 0; i < lst.length(); i++)
				{
					var x:XMLList = lst[i].children();
 
					for(var j:int = 0; j < x.length(); j++)
					{
						if(x[j].@inputtype == 'TextInput')
						{
							var frmItem:FormItem = new FormItem();
							frmItem.direction = "horizontal";
							frmItem.label = x[j].@formlabel;
							// make sure boolean is pasrsed to a string before assigned 
							// to required property of the formitem
							var validString : String = x[j].@required;
							var valid : Boolean = (validString == "true"); 
							frmItem.required = valid;
 
							var tb:TextInput = new TextInput();
							tb.text = x[j];
							frmItem.addChild(tb);
 
 
							userInfoForm.addChild(frmItem);
						}
						else if(x[j].@inputtype == 'ComboBox')
						{
 
							var frmItemCB:FormItem = new FormItem();
							frmItemCB.direction = "horizontal";
							frmItemCB.label = x[j].@formlabel;
							// make sure boolean is pasrsed to a string before assigned 
							// to required property of the formitem
							var validString : String = x[j].@required;
							var valid : Boolean = (validString == "true"); 
							frmItemCB.required = valid;
 
							// make sure the string is split, assigned to an array, and parsed 
							// to an arraycollection to assgn it as dataprovider for dropdownlist 
							var str:String = x[j];
							var arr:Array = str.split(","); 
							var arrcol:ArrayCollection = new ArrayCollection;
 
							for(var k:int = 0; k < arr.length; k++)
							{
								var obj:Object = {name:arr[k]}
								arrcol.addItem(obj);
							}
 
							var cb:DropDownList = new DropDownList();
							cb.dataProvider = arrcol;
							cb.labelField = "name";
							frmItemCB.addChild(cb);
 
 
							userInfoForm.addChild(frmItemCB);
						}
						else if(x[j].@inputtype == 'RadioButtonGroup')
						{
 
							var frmItemRB:FormItem = new FormItem();
							frmItemRB.direction = "horizontal";
							frmItemRB.label = x[j].@formlabel;
							// make sure boolean is pasrsed to a string before assigned 
							// to required property of the formitem
							var validString : String = x[j].@required;
							var valid : Boolean = (validString == "true"); 
							frmItemRB.required = valid;	
 
							var frmItemRB1:FormItem = new FormItem();
							frmItemRB1.addChild(label);
 
							var y:XMLList = x[j].children();
							var radioGroup:mx.controls.RadioButtonGroup = new mx.controls.RadioButtonGroup();
							radioGroup.addEventListener(ItemClickEvent.ITEM_CLICK,
								radioGroup_itemClick);
							for(var l:int = 0; l < y.length(); l++)
							{								
								var rb:mx.controls.RadioButton= new mx.controls.RadioButton;
								rb.label = y[l];
								rb.group = radioGroup;
 
								frmItemRB.addChild(rb);									
 
								userInfoForm.addChild(frmItemRB);
							}
						}							
					}
				}
			}
			public var label:TextInput = new TextInput();
			private function radioGroup_itemClick(evt:ItemClickEvent):void {
 
				label.text = evt.label ;
			}
			/**
			 * Helper function that returns all the fields for a
			 * given form. Pass in requiredOnly = true if you only want
			 * the required fields.
			 */
			private function getFields(form:Form, requiredOnly:Boolean=false):Array
			{
				var a:Array = [];
				// get every child of the Form
				var formItems:Array = form.getChildren();
				for (var i:int=0; i<formItems.length; i++)
				{
					// make sure it's a FormItem - if you use FormHeading or have
					// items that are not wrapped in a FormItem tag then ignore those
					if (formItems[i] is FormItem)
					{
						var formItem:FormItem = formItems[i];
						// add the formItem's child to the array.
						// if you only need required items, set requiredOnly = true
						// Note: this assumes you only have one form field per FormItem
						//       You could easily add additional logic here for more
						if (formItem.required || !requiredOnly)
							a.push(formItem.getChildAt(0));
					}
				}
				return a;
			}
 
			/**
			 * Validates all fields in a given form.
			 */
			private function validateForm(form:Form):Boolean
			{
				// reset the flag
				var _isValid:Boolean = true;
				var _notValid:Boolean = false;
 
				// populate the fields - if your fields aren't dynamic put this in creationComplete
				var fields:Array = getFields(form, true);
 
				for each(var source:UIComponent in fields)
				{
					// create a simple string validator
					var stringValidator:StringValidator = new StringValidator();
					stringValidator.minLength = 2;
					stringValidator.source = source;
					stringValidator.property = "text";
					stringValidator.requiredFieldError = "This field is required!!!";
 
					var numberValidator:NumberValidator = new NumberValidator();
					numberValidator.minValue = 0;
					numberValidator.source = source;
					numberValidator.property = "text";
					numberValidator.lowerThanMinError = "This field is required!!!";
 
					var rbValidator:StringValidator = new StringValidator();
					rbValidator.minLength = 1;
					rbValidator.maxLength = 80;
					rbValidator.source = source;
					rbValidator.property = "selectedValue";
					rbValidator.requiredFieldError = "This field is required!!!";
 
					var result:ValidationResultEvent;
					//var radiogroup:spark.components.RadioButtonGroup = new spark.components.RadioButtonGroup;
					// typical validation, but check to this checks for any different
					// types of UIComponent here
					if (source is TextInput)
						result = stringValidator.validate(TextInput(source).text)
					else if (source is TextArea)
						result = stringValidator.validate(TextArea(source).text)						
					else if (source is DropDownList)
						result = numberValidator.validate(DropDownList(source).selectedIndex)
					else if (source is Label)
						result = stringValidator.validate(Label(source).text)
						//if(source is spark.components.RadioButton)
						//result = numberValidator.validate(mx.controls.RadioButton(source))
 
					// if the source is valid, then mark the form as valid
					_isValid = (result.type == ValidationResultEvent.VALID) && _isValid;						
				}					
				return _isValid;
			}
 
 
			protected function submitButton_clickHandler(event:MouseEvent):void
			{
				if(validateForm(userInfoForm) == true)
				{
					Alert.show("Proceed Genius!!!","Alert");
				}
				else
				{
					Alert.show("Open ur eyes and fill the form properly u morron!!!","Morron");
				}
			}
 
		]]>
	</fx:Script>
 
	<fx:Declarations>
		<!--Below line can be used for XML from an external source-->
		<!--<mx:HTTPService fault="errorHandler(event)" id="XMLService" resultFormat="e4x" url="formdata.xml" result="resultHandler(event)" />-->
	</fx:Declarations>
 
	<s:VGroup horizontalCenter="0" verticalCenter="0">
		<mx:Form id="userInfoForm"  />
		<s:Button label="Submit" id="submitButton" click="submitButton_clickHandler(event)"/>	
	</s:VGroup>
 
</s:Application>

One Response to “Dynamic form Generation / Rendering / Validation using XML – in Flex”

  1. Alfredo says:

    a bit off topic. my apologies for that. i’ve been foiwllong your blog for quite sometime.i have a requirement to display a timeline[gantt] chart in flex. for this i have used an adv data grid. the chart will display data for 60 mins when it gets loaded for the first time. the user will have an option to drill down further to see 5 min data or 30 min data instead of the whole 60 min. in that case, the data grid should be redrawn including the columns. how to achieve this?as of now, i am calling the invalidateDisplayList function of the component. but when i tried adding trace statements, i found that the invalidateDisplayList and updateDisplayList functions are getting called three times.my requirement is the data grid should get redrawn whenever the data provider changes[including the no of columns, as its variable]can you help me out.

Top
Follow

Get every new post delivered to your Inbox

Join other followers