So as I am sure you are aware, Flex 2 hit the ground running recently. Have you been kicking yourself for not getting a head start on learning? Well for all the people who thought it was just a fad, this tutorial is here to save the day. I hope by reading and working through this tutorial you will get a general but firm understanding of simple to advanced workings of Flex.
Dowload associated content "userManager.zip"
What is Flex? You might ask yourself. Flex is the most complete, powerful application development solution for creating and delivering cross-platform rich Internet applications (RIAs) within the enterprise and across the web. It enables the creation of expressive and interactive web applications that can reach virtually anyone on any platform. Enterprises can use Flex to quickly build and deploy applications that improve the user experience, boost the bottom line, and analyze data to enable better business decisions.
Okay, with out further ado, lets get cracking.
This tutorial will be broken up into 4 stages.
As with any IDE, learning to use the IDE takes big chunk of time when you are trying to teach yourself. In this stage you will learn how to create a basic Flex project. This basic Flex project will be the starting point of our over all end result. So, lets not skip this part.
Step 1: How will you connect to your data.
There are basically 3 ways you can connect to your data from Flex.
A. XML or Webservices
B. RemoteObjects
C. HttpService
For this tutorial we will be using option A, webservices. I would have liked to use RemoteObjects, but since this is written for the masses and since some people cannot update their CF server to Mystic we will be going with webservices.
Okay, enough of the background stuff, lets start this.
Start off by going to File > New > Flex Project. You will get a screen like the one in figure 1. As I said before we will be using Webservices, so go ahead and select Basic and click next.

Step 2: Naming your project.
Here is where we give our project a name. For this tutorial we will be using the project name userManager. You have one other option on this screen (figure 2). You can change the default location of where you would like to store your project. For this tutorial we will be using the default location of My Documents\Flex Builder\<project name>. Once you have given your project a name, click finish and your Flex project will be created.

Step 3: Hold your horses.
Okay, so you have a nice new project with that fresh project smell. But this is where we close Flex builder and move on to other tasks. I know, I know, you just got started and already it is being taken away. Know there is a method to the madness, and remember we are working on a 3 tier system here folks. So, we want to start back to front.
As with most web applications, you need to be able to store your data, so of course we will be using the old standby of a database. For this tutorial, I will be using MYsql.
Step 1: Create your database.
In this tutorial we will be using the database name userManager. Below you will find an SQL query to create your table and fields.
SET FOREIGN_KEY_CHECKS=0;
use userManager;
#----------------------------
# Table structure for users
#----------------------------
CREATE TABLE `users` (
`fld_userId` varchar(30) NOT NULL default ',
`fld_userLogin` varchar(20) default NULL,
`fld_userPass` varchar(30) default NULL,
`fld_userFirstName` varchar(50) default NULL,
`fld_userLastName` varchar(50) default NULL,
`fld_userEmail` varchar(255) default NULL,
`fld_userUrl` varchar(255) default NULL,
`fld_userSex` int(1) default NULL,
PRIMARY KEY (`fld_userId`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
#----------------------------
# No records for table users
#----------------------------
As stated previously we will be creating a webservice that will allow users to connect to our data. For this we will be creating a Coldfusion Component aka CFC.
Step 1: Server preparation.
As with most web applications, there is normally some amount of preparation you have to do in order to get your project off the ground. First we need to create a file called crossdomain.xml.
The crossdomain.xml file permits your compiled SWF to access your data source (CFC). You can find more info on this file on the Adobe website, www.adobe.com/go/14213
crossdomain.xml - copy the code below, and put it in your crossdomain.xml file. You can adjust the permissions, by placing your domain name
in the domain attribute. Remember, you can not access other domains if they do not have the permissions file. However, you can by pass this with a simple proxy via CF, ASPX, PHP, etc...
Your crossdomain.xml file, must reside in your document root. If your document root is /var/www/html/userManager/ You would place your crossdomain.xml
file, in your userManager folder. IE /var/www/html/userManager/crossdomain.xml
<cross-domain-policy>
<allow-access-from domain="*"/>
</cross-domain-policy>
Next we need to create our folder structure. In order to keep it simple, we will use a simple folder structure. In your document root create a new
directory called com. For example, if your document root was /var/www/html/userManager. We will be using this as our document root for the remainder of this tutorial.
Step 2: Data Source
Next we need to create a data source, for this tutorial we will be using the data source name cf_userMan
Step 3: Create our CFC.
This part is pretty straightforward and easy. First thing we need to do is create a new CFC. Start a new document in your favorite editor. In the document add the code below, and save it to your documentroot/com directory. Name the CFC UserManager. You should end up with something like.
<cfcomponent displayname="UserManager">
</cfcomponent>
Step 4: Add User Function
Now we are ready to get into some code. We are going to start off by creating our function in our CFC.
Here you can see we have a pretty simple function. The two main things that allow a Flex application to connect to a CFC are:
1. Access to the function must be remote.
2. The arguments you pass from Flex to your function must match exactly. This seems pretty straightforward, but a lot of developers make this simple mistake.
This is our first function in our webservice. From Flex we are passing 7 arguments, and these arguments are used to insert data into our database. Copy the code below into your UserManager.cfc. (make sure it is between your cfcomponet tags).
<!--- ADD A NEW USER FUNCTION --->
<cffunction name="Add_User" access="remote" returntype="string">
<!--- VARS PASSED FROM FLEX TO CFC --->
<cfargument name="login" required="yes" type="string" />
<cfargument name="pass" required="yes" type="string" />
<cfargument name="firstName" required="yes" type="string" />
<cfargument name="lastName" required="yes" type="string" />
<cfargument name="email" required="yes" type="string" />
<cfargument name="url" required="no" type="string" />
<cfargument name="sex" required="no" type="string" />
<!--- INSERTION QUERY --->
<cfquery name="AddUserQry" datasource="#application.dsn#">
insert into users (fld_userId, fld_userLoing, fld_userPass, fld_userFirstName, fld_userLastName, fld_userEmail, fld_userUrl, fld_userSex)
values
('#createUUID()#', '#arguments.login#', '#arguments.pass#', '#arguments.firstName#', '#arguments.lastName#', '#arguments.email#',
'#arguments.url#', '#arguments.sex#')
</cfquery>
<!--- CONFIRMATION MESSAGE --->
<cfset msg = "You have sucessfully added #arguments.firstName# #arguments.lastName# as a user">
<cfreturn msg />
</cffunction>
Step 5: Update User Function
Here we have our next function. In this function, we have a new argument being passed from our Flex application to our CFC. We are now passing the user's id from the Flex application to our CFC, we are using the id as a PK.
<!--- UPDATE A USER FUNCTION --->
<cffunction name="Edit_User" access="remote" returntype="string">
<!--- VARS PASSED FROM FLEX TO CFC --->
<cfargument name="id" required="yes" type="string" />
<cfargument name="login" required="yes" type="string" />
<cfargument name="pass" required="yes" type="string" />
<cfargument name="firstName" required="yes" type="string" />
<cfargument name="lastName" required="yes" type="string" />
<cfargument name="email" required="yes" type="string" />
<cfargument name="url" required="no" type="string" />
<cfargument name="sex" required="no" type="string" />
<!--- INSERTION QUERY --->
<cfquery name="EditUserQry" datasource="cf_userMan">
update users
set
fld_userLogin = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.login#" />,
fld_userPass = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.pass#" />,
fld_userFirstName = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.firstName#" />,
fld_userLastName = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.lastName#" />,
fld_userEmail = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.email#" />,
fld_userSex = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.sex#" />
where fld_userId = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.id#" />
</cfquery>
<!--- CONFIRMATION MESSAGE --->
<cfset msg = "You have sucessfully updated #arguments.firstName# #arguments.lastName#" />
<cfreturn msg />
</cffunction>
Step 6: User Delete Function
This next function is how we are going to remove users from the system. We only have one argument passed with this function, it is our pk id.
<!--- DELETE A USER FUNCTION --->
<cffunction name="Delete_User" access="remote" returntype="string" >
<cfargument name="id" required="yes" type="string" />
<cfquery name="DeleteUserQry" datasource="cf_userMan">
delete from users
where fld_userId = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.id#" />
</cfquery>
<cfreturn msg />
</cffunction>
Step 7: User Display Function
This function is a bit different then previous functions. In this function we are returning our data as a struct. Why do we do this is simply because it is the easiest and best way to display returned query objects within Flex. Again, we are only passing the id argument into this function.
<!--- DISPLAY USER INFO ON EDIT SCREEN --->
<cffunction name="Display_User" access="remote" returntype="struct" >
<cfargument name="id" required="yes" type="string" />
<cfquery name="DisplayUserQry" datasource="cf_userMan" >
select
fld_userId, fld_userLogin, fld_userPass, fld_userFirstName,
fld_userLastName, fld_userEmail, fld_userUrl, fld_userSex
from users
where fld_userId = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.id#" />
</cfquery>
<cfset userInfo = structNew()>
<cfscript>
userInfo['id'] = DisplayUserQry.fld_userId;
userInfo['login'] = DisplayUserQry.fld_userLogin;
userInfo['pass'] = DisplayUserQry.fld_userPass;
userInfo['firstName'] = DisplayUserQry.fld_userFirstName;
userInfo['lastName'] = DisplayUserQry.fld_userLastName;
userInfo['email'] = DisplayUserQry.fld_userEmail;
userInfo['url'] = DisplayUserQry.fld_userUrl;
userInfo['sex'] = DisplayUserQry.fld_userSex;
</cfscript>
<cfreturn userInfo />
</cffunction>
Step 8: User Search Function
The last function in our CFC is the user search function. In this function we are going to return the actual query object to Flex. We do not need to convert our query into a struct for this. You can use an Array of Structures to obtain the same results, but this is not required for this tutorial.
<!--- USER SEARCH --->
<cffunction name="Search_User" access="remote" returntype="query" >
<cfargument name="firstName" required="no" />
<cfargument name="lastName" required="yes" />
<cfquery name="SearchUserQry" datasource="cf_userMan">
select
fld_userFirstName, fld_userLastName
from users
where
fld_userLastName like '%#arguments.lastName#%'
<cfif arguments.firstName neq "">
and fld_userFirstName like '%#arguments.firstName#%'
</cfif>
</cfquery>
<cfreturn SearchUserQry />
</cffunction>
Stage 4: Lets write some Flex code
In this stage we are going to break the 5 operations into 5 simple steps. We are going to start with a simple load screen, then a simple search operation, then move on to a creation operation, then to our display/update operation and lastly we are going to write out delete operation.
Before we start to write any code we need to setup our file structure. In your project directory root, create a new folder called custom (fig 3). This is where we will store all the custom flex components that we will create in this stage. Inside the custom folder you just created, create another folder called as (fig 4). This is where we will store all our external action script files.


Step 1: In this step we are going to create a simple loading screen to handle all of our custom components. This screen will allow us to load all of our search screens, add user, edit user, and delete user screens.
So here we go. Starting off, we are going to open the Flex file we created at the start of this tutorial. Now that we have it open lets start modifying it.
This is our complete userManager.mxml file. In the mx:Application tag you will see the defined named spaces. These are qualified by the xmlns attribute. By default, we have the standard Adobe name space (xmlns:mx="http://www.adobe.com/2006/mxml"). This default xmlns allows you refer to more than one set of XML tags in the same XML document. Next, notice that there is another xmlns tag defined. This is our name space to our custom components that we will create further on in this tutorial (xmlns:custom="custom.*"). This will allow us to make custom tag calls with in the Flex application.
The last important thing to note is out first custom component call we will make. On line 3 we have a new tag to use, the tag uses the tag root custom which matches up with the name space we created in our Application tag.
This is all we will do with our userManager.mxml file. As far as we are concerned this file is complete.
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:custom="custom.*" layout="absolute">
<custom:userSearch />
</mx:Application>
Step 2: User Search Operation
In this step we are going to write a complete user search screen from start to finish. Starting off we are going to create our layout of the screen. This includes our search inputs, buttons, and our display data grid.
Step 2a: Creating our first custom component - User Search
This step is the beginning of our Flex development. In this step we will create our user search screen. First we need to create a new Flex Component. To do this, go to file > new> MXML Component. This will bring up the screen you see in fig 5. Select the project UserManager, then select the folder custom. Name the file userSearch, change the based on drop down to Panel, leave the layout set to absolute and set the width and height to 100%.
Your New MXML Component screen show look like fig 6. Once this is done click okay, and you have just created your first Flex component.


Now that our component has been created, lets get into the fun stuff of building our first set of custom components. We will create forms, text inputs, buttons, and display data grids. This can be done in two ways. You can drag and drop your Flex components from the components panel(fig 7), or you can hand code the inputs.
####IMAGE HERE - Fig 7#####
As with our userManager.mxml file, you will notice that we have a lot of the same code here aside from the Application tag is replaced with the Panel tag. The panel tag allows us to create various form components, image components and other fun flex components in a easy to use and simple interface.
First thing we need to do is add a title to the panel, this will allow us to show the user what they are viewing. We are going to name our panel User Search.
<?xml version="1.0" encoding="utf-8"?>
<mx:Panel xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" width="100%" height="100%" title="User Search">
</mx:Panel>
Now that we have our base display component created, we need to add some form inputs to the panel.
The Form container lets you control the layout of a form, mark form fields as required or optional, handle error messages, and bind your form data to the Flex data model to perform data checking and validation. It also lets you use style sheets to configure the appearance of your forms.
The FormItem container defines a label and one or more children arranged horizontally or vertically. Children can be controls or other containers.
Below you will see that we have created two Forms. We are using these forms to hold our form items that will display the form label and hold the FormItem children. Inside the FormItem we have created the form child TextInput.
The TextInput control is a single-line text field that is optionally editable. We have given our TextInput controls the id firstName and lastName. If you remember we gave these same id's to our arguments that we are passing into our CFC. Doing this is not required. You can give your TextInput controls any id you like.
<mx:Form x="10" y="10">
<mx:FormItem label="First Name:">
<mx:TextInput id="firstName"/>
</mx:FormItem>
</mx:Form>
<mx:Form x="259" y="10">
<mx:FormItem label="Last Name" required="true">
<mx:TextInput id="lastName"/>
</mx:FormItem>
</mx:Form>
Now we need to create a button. This will allow us to perform actions within our Flex application such as saves, edits, displays, and deletes. The Button control is a commonly used rectangular button. Button controls look like they can be pressed. They can have a text label, an icon, or both on their face. You will notice that I have added the label attribute to the button, and given it the value Search. This label is what will be displayed to the user.
<mx:Button x="537" y="25" label="Search"/>
The last component that we need to create is a display datagrid. The DataGrid control is a like a List except that it can show more than one column of data, making it suited for showing objects with multiple properties.
Below we have our datagrid, this datagrid will be used to display and pass data from our datagrid to our edit user screen. As with most components, we have given our datagrid the id userDG.
The next thing to look at is our DataGridColumns. The DataGridColumn class describes a column in a DataGrid control. There is one DataGridColumn per displayable column, even if a column is hidden or off-screen. In our datagrid, we have a total of eight DataGridColumns. Three of our columns are being used to display data to the user. The other six columns are hidden and are being used to display data in our edit user screen.
In our first three columns we have defined the attribute headerText, which is used to display the header for the visible column. We have also defined the attribute dataField in our column. This attribute is the name of the column, struct object, or array of structs object we are passing from our backend. Since we are returning our objects as a query object, our datafields are uppercase versions of our database fields.
In our other six columns we have defined the attribute visible and set the value to false. This will keep the columns hidden from the users view. As with our first three columns, we are using the uppercase versions of our returned query objects.
<mx:DataGrid x="10" y="72" id="userDG" height="100%" width="100%">
<mx:columns>
<mx:DataGridColumn headerText="First Name:" dataField="FLD_USERFIRSTNAME"/>
<mx:DataGridColumn headerText="Last Name:" dataField="FLD_USERLASTNAME"/>
<mx:DataGridColumn headerText="Email:" dataField="FLD_USEREMAIL"/>
<mx:DataGridColumn visible="false" dataField="FLD_USERLOGIN"/>
<mx:DataGridColumn visible="false" dataField="FLD_USERPASS"/>
<mx:DataGridColumn visible="false" dataField="FLD_USERURL"/>
<mx:DataGridColumn visible="false" dataField="FLD_USERSEX"/>
<mx:DataGridColumn visible="false" dataField="FLD_USERID"/>
</mx:columns>
</mx:DataGrid>
With our base application structure completed, we will now move on to creating the connections from our flex application to our back end. As stated at the beginning of this tutorial, we are going to be using the Webservice class. The WebService class provides access to SOAP-based web services on remote servers.
Within our Webservice tag we have defined several attributes. Our webservice tag has been given the id SearchManager. Our next attribute useProxy has been given the value false. By default the useProxy is false, if your webservice requires a proxy to make SOAP calls you will need to set this attribute value to true. The wsdl attribute is the location of the wsdl document for this webservice. The last attribute in our tag is showBusyCursor. If this attribute is set to true, the users mouse cursor will display activity within the application by changing the mouse pointer to a clock.
<mx:WebService id="SearchManager" useProxy="false" wsdl="com/UserManager.cfc?wsdl" showBusyCursor="true">
</mx:WebService>
Now the webservice is created we need to create an operation with in the webservice. An Operation is an individual method on a service. An Operation can be called either by invoking the function of the same name on the service or by accessing the Operation as a property on the service and calling the send() method.
Here we have a single operation, and within this operation we have several attributes that need to be defined.
First off, we have the name attribute. This attribute is given the name of the method/function that we created in our CFC. The value of the operation must match both case/function name value exactly.
Next we have our result attribute. This attribute is defined as the returned results that we get back from our back end. The value of the result attribute is a combination of the name of the webservice, the name of the method we are calling from our back end, and we add a defining name to the function by adding result to the end of it. This combination creates the name of our function. Tagged onto the end of our named function you will see that we are also creating a object type for our results method call. This is defined as webserviceName.methodName.results. The last object type lastResult allows you to bind RPC component objects to the properties of other objects, including user-interface components and data models.
The last attribute in our operation is our fault attribute. This attribute works in the same way as our result attribute. We define our function name by combining the webservice name, method name, and adding a function defining name to the end of it. This now creates our named fault function. As with our result attribute we have defined an object type. Instead of defining the return object, we are defining an event. The properties of the Event class carry basic information about an event, such as the event's type or whether the event's default behavior can be canceled.
<mx:WebService id="SearchManager" useProxy="false" wsdl="com/UserManager.cfc?wsdl" showBusyCursor="true">
<mx:operation name="Search_User"
result="SearchManager_Search_User_Result( SearchManager.Search_User.lastResult )"
fault="SearchManager_Search_User_Fault(event)"/>
</mx:WebService>
With our completed webservice we need to add in some validation to our search. This will allow us to mandate which required information the user must pass and which information is optional.
The first thing we need to create is a validation model. You use the <mx:Model> tag to declare a data model in MXML. An <mx:Model> tag is compiled into a tree of Action Script objects; the leaves of the tree are scalar values.
Within our model we have defined the xml tag LastName, and we have given the output of this tag the value of our lastName TextInput control.
<mx:Model id="CheckModel">
<LastName>{lastName.text}</LastName>
</mx:Model>
The next thing we need to do is create a StringValidator. The StringValidator class validates that the length of a String is within a specified range. Within our StringValidator tag, we have several defined attributes.
The source attribute is defined by the name of the text input control we are validating. In our StringValidator we are validating our lastName text input.
The required attribute is defined by either true or false. If the value of the required attribute is true, the text input must fall within the ranges set by the minLength and maxLength attributes.
The Property attribute defines what type of information we are trying to pass. For our validator we are using the property value of text since we are passing data from our text input control
The last two attributes within our validator are minLenth and maxLength. These two attributes create a min and max range of string length for the information we are trying to pass.
<mx:StringValidator source="{lastName}" required="true" id="lastNameVal" property="text" minLength="1" maxLength="20" />
Step 2b: Creating the Action Script for our User Search
This is our first step into creating the second part of a Flex application. In this section we will create several functions that will validate data, initialize save functions, and pass data to our edit user screen. We need create a new Action Script file called asUserSearch.as. To do this go to file>New>Action Script File. Give the file the name asUserSearch.as and click finish. We now have our first Action Script file.
The next thing we need to do is import our classes into our Action Script file. A Class object is created for each class definition in a program. Every Class object is an instance of the Class class. The Class object contains the static properties and methods of the class. The class object creates instances of the class when invoked using the new operator. You do this by using the Import operator.
Here we have imported several Action Script classes into our Action Script file. In your Action Script code, instead of referring to the class with its fully qualified package name (MyPackage.Util.MyClass), you refer to it as MyClass.
import mx.controls.Alert;
import mx.events.ValidationResultEvent;
import mx.rpc.events.AbstractEvent;
import mx.rpc.events.FaultEvent;
import mx.utils.ObjectUtil;
import flash.events.*;
import mx.managers.PopUpManager;
import mx.core.IFlexDisplayObject;
import mx.events.CloseEvent;
Now that we have our classes imported, we are going to move on to writing our first function. The first function we are going to write is going to be our validator function.
Here is our first function, starting off we are creating a private variable. The variable we are creating is named VlastName, along with defining the variable name we are defining the object type. We are using the class object type ValidationResultEvent. The ValidationResultEvent class represents the event object passed to the listener for the valid validator event or the invalid validator event.
Next we will create our function. First, we need to give the function a name. For this function we will give it the name of userSearchValidation. We are also defining the object type with void. The void object type specifies that a function cannot return any value.
Within our function we are setting our previously defined variable VlastName to the value of our StringValidator.
The last part of our function is to compare our variable against our validator. If the validator fails, our string validator that we previously created will alert the user. If the validator succeeds, we call a function that we will create later in this step.
// DEFINE VARS FOR STORING VALIDATION OBJECTS
private var VlastName:ValidationResultEvent
// FUNCTION TO VALIDATE, IF VALID SAVE FORM, IF NOT VALID SHOW ERRORS
private function userSearchValidation():void{
// Validate FORM INPUTS
VlastName = lastNameVal.validate();
if (VlastName.type==ValidationResultEvent.INVALID){
return;
}
else{
userSearchHandler();
}
}
Now that we have our validator out of the way, we are going to create our search functions.
This is the first function we need to create to start our search function section. Within this function we are passing two parameters, firstName and lastName. If you remember, these are the same arguments that we are passing into our CFC. These parameters must match in both case/parameter name. You will notice that the action we are performing inside this function is defined as WebServiceName.MethodName(parameters). This calls our webservice, tells the webservice which method to call, and tells the method which parameters to pass.
// CALL USER SEARCH METHOD
private function SearchManager_Search_User(firstName, lastName){
SearchManager.Search_User(firstName, lastName)
}
The next function we need to create for our search function section is our result function. In this function we have one parameter being passed back from our CFC. We define this parameter as result, which will be used to pass data to other component objects.
In the function we check to see if the return query object length is greater than zero. If the returned object is greater than zero, we set the dataProvider for our previously created datagrid to the returned query object. This will populate the columns with the information from our database. If the returned query object is not greater than zero, we create an Alert window.
The alert control we create contains a defined string notifying the user that there are no records matching their search parameters. The Alert control is a pop-up dialog box that can contain a message, a title, buttons (any combination of OK, Cancel, Yes, and No) and an icon. The Alert control is modal, which means it will retain focus until the user closes it. Within our alert control we have added the event listener alertClickHandler which is a function we will create further into this tutorial. Event listeners, which are also called event handlers, are functions that Flash Player executes in response to specific events. The last part of our else statement is to remove all the data object assigned to our datagrid. We do this by using the removeAll() object type.
// HANDLE USER SEARCH RESULTS
private function SearchManager_Search_User_Result(result):void{
if (result.length > 0){
userDG.dataProvider = result;
}
else{
Alert.show("No users found. Create a new one?", "Program Alert", 3, this, alertClickHandler);
userDG.dataProvider.removeAll();
}
}
The next part of our search function section is our Fault function. This function will display any faults that are returned from our search.
In this function we are returned a single parameter with the object type class of FaultEvent. This event is dispatched when an RPC call has a fault. If the RPC call does fault, we display a simple error message to the user
// HANDLE USER SEARCH FAULTS
private function SearchManager_Search_User_Fault(event:FaultEvent):void{
Alert.show("An error occured","Program Error")
}
The next step we need to do is to create our search handler. This handler will allow us to define what information is passed to the back end.
In this function we check against the length of the firstName text input control. If the text input control is greater than zero, we call our previously created search function, then pass both the firstName text input value and the lastName text input value. If the text input control length is not greater than zero, we call our previously created search function, then we pass an empty string and the value of the lastName text input.
// USER SEARCH HANDLER
private function userSearchHandler(){
if (firstName.length > 0){
SearchManager_Search_User(firstName.text,lastName.text)
}
else{
SearchManager_Search_User("",lastName.text)
}
}
The very last function we need to create is our event listener that we used within our Alert control. In this function we check against what the user selected in our Alert control, if the user selected Yes, we call the function showUserDetail() which we will create next. If the user selected no, we remove the pop up.
// EVENT HANDLER FOR ALERT SELECTED OPTION
private function alertClickHandler(event:CloseEvent):void {
if (event.detail==Alert.YES)
showUserDetail()
else
return;
}
The next function we create will allow us to call the add/edit user screen which is included in the tutorial source folder. In this function we have to create new classes. These new classes allow us to create pop up windows. These pop up windows will be used to add/edit users.
Starting off, we will name our function showUserDetail() and give the function the object type void. The next thing we need to do is define a variable that has the custom object type userDetail. This is the name of the custom component included in the tutorial source folder. We set the value of this custom component to the name of the add/edit user component.
Next we call the class PopUpManager. The PopUpManager singleton class creates new top-level windows and places or removes those windows from the layer on top of all other visible windows. We do this by defining the method type createPopUp. CreatePopUp creates a top level window and places it above other windows in the z-order. Within the createPopUp method we define the parameters of the pop up window.
Within our function we have yet another if/else statement. We are checking against the selectedItem. If the user has selected a record within our datagrid we then populate the popup window with the data from the datagrid. We do this by referencing the var.textInputControl.text. This will set the value of the text input control of our add/edit user screen to the value of the selectedItem of our datagrid.
If the user does not have a selectedItem, we create the pop up and allow the user to create a new user. We are not passing any information to the pop up window. We do this by using the return operator.
// CALL USER ADD COMPONENT
private function showUserDetail():void{
var popUp:userDetail = userDetail(
PopUpManager.createPopUp(this, userDetail, true))
if (userDG.selectedItem){
popUp.uuid.text = userDG.selectedItem.FLD_USERID;
popUp.login.text = userDG.selectedItem.FLD_USERLOGIN;
popUp.pass.text = userDG.selectedItem.FLD_USERPASS;
popUp.firstName.text = userDG.selectedItem.FLD_USERFIRSTNAME;
popUp.lastName.text = userDG.selectedItem.FLD_USERLASTNAME;
popUp.email.text = userDG.selectedItem.FLD_USEREMAIL;
popUp.url.text = userDG.selectedItem.FLD_USERURL;
popUp.sex.selectedIndex = userDG.selectedItem.FLD_USERSEX;
}
else{
return;
}
}
Step 3: Finalizing our search application
Now that we have our complete Action Script file, we need to make a few minor modifications to our userSearch.mxml file. Therefore, we can call these functions from the controls we created.
The first thing we need to do to call the functions we just created within our Action Script file is to include the Action Script into our Flex application. We do this by using the Script tag. You use the <mx:Script> tag to define blocks of Action Script code. Action Script blocks can contain variable and function definitions. You can place blocks of Action Script code in the body of the tag, or you can include an external file by specifying the source with the source property of the tag as shown below:
<mx:Script source="as/asUserSearch.as" />
Now that we have included our Action Script file into our Flex application, we need to assign the functions to our components. You can call functions in various ways. To keep this simple, we will be using the enter, and click events.
First, let's add our search function to our lastName text input control. We do this by adding the event attribute enter to the text input control and set the value of this attribute to the function name of our validator function. This will allow a user to hit the enter key and preform the search.
<mx:TextInput enter="userSearchValidation()" id="lastName"/>
Next we will add the search function to our button control. We will do this by adding the event click attribute to the button control and set the value of this attribute to the function name of our validator function. This will allow a user to click the button and perform the search.
The last function we need to assign to our Flex components is to assign the showUserDetail function to our datagrid. We will do this by adding the attributes doubleClickEnabled and doubleClick. We define the value of the doubleClickEndabled attribute to true. This attribute must be true, and be defined to use the doubleClick event. We then define the doubleClick attribute and set the value of this attribute to showUserDetail().
<mx:DataGrid x="10" y="72" doubleClickEnabled="true" doubleClick="showUserDetail()" id="userDG" height="100%" width="100%">
Your final user search source should look like the source below.
userSearch.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Panel xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" width="100%" height="100%" title="User Search">
<!-- VALIDATOR MODEL -->
<mx:Model id="CheckModel">
<LastName>{lastName.text}</LastName>
</mx:Model>
<!-- INCLUDE EXTERNAL AS -->
<mx:Script source="as/asUserSearch.as" />
<!-- SEARCH WEBSERVICE -->
<mx:WebService id="SearchManager" useProxy="false" wsdl="com/UserManager.cfc?wsdl" showBusyCursor="true">
<mx:operation name="Search_User"
result="SearchManager_Search_User_Result( SearchManager.Search_User.lastResult )"
fault="SearchManager_Search_User_Fault(event)"/>
</mx:WebService>
<mx:Form x="10" y="10">
<mx:FormItem label="First Name:">
<mx:TextInput id="firstName"/>
</mx:FormItem>
</mx:Form>
<mx:Form x="259" y="10">
<mx:FormItem label="Last Name" required="true">
<mx:TextInput enter="userSearchValidation()" id="lastName"/>
</mx:FormItem>
</mx:Form>
<mx:Button x="537" y="25" label="Search" click="userSearchValidation()"/>
<mx:DataGrid x="10" y="72" doubleClickEnabled="true" doubleClick="showUserDetail()" id="userDG" height="100%" width="100%">
<mx:columns>
<mx:DataGridColumn headerText="First Name:" dataField="FLD_USERFIRSTNAME"/>
<mx:DataGridColumn headerText="Last Name:" dataField="FLD_USERLASTNAME"/>
<mx:DataGridColumn headerText="Email:" dataField="FLD_USEREMAIL"/>
<mx:DataGridColumn visible="false" dataField="FLD_USERLOGIN"/>
<mx:DataGridColumn visible="false" dataField="FLD_USERPASS"/>
<mx:DataGridColumn visible="false" dataField="FLD_USERURL"/>
<mx:DataGridColumn visible="false" dataField="FLD_USERSEX"/>
<mx:DataGridColumn visible="false" dataField="FLD_USERID"/>
</mx:columns>
</mx:DataGrid>
<!-- VALIDATORS -->
<mx:StringValidator source="{lastName}" required="true" id="lastNameVal" property="text" minLength="1" maxLength="20" />
</mx:Panel>
asUserSearch.as
//Imported Classes
import mx.controls.Alert;
import mx.events.ValidationResultEvent;
import mx.rpc.events.AbstractEvent;
import mx.rpc.events.FaultEvent;
import mx.utils.ObjectUtil;
import flash.events.*;
import mx.managers.PopUpManager;
import mx.core.IFlexDisplayObject;
import mx.events.CloseEvent;
//*****************VALIDATION START****************************************
// DEFINE VARS FOR STORING VALIDATION OBJECTS
private var VlastName:ValidationResultEvent
// FUNCTION TO VALIDATE, IF VALID SAVE FORM, IF NOT VALID SHOW ERRORS
private function userSearchValidation():void{
// Validate FORM INPUTS
VlastName = lastNameVal.validate();
if (VlastName.type==ValidationResultEvent.INVALID){
return;
}
else{
userSearchHandler();
}
}
//*****************VALIDATION END******************************************
//-------------------------------------------------------------------------
//*****************USER SEARCH FUNCTIONS START*****************************
// CALL USER SEARCH METHOD
private function SearchManager_Search_User(firstName, lastName){
SearchManager.Search_User(firstName, lastName)
}
// HANDLE USER SEARCH RESULTS
private function SearchManager_Search_User_Result(result):void{
if (result.length > 0){
userDG.dataProvider = result;
}
else{
Alert.show("No users found. Create a new one?", "Program Alert", 3, this, alertClickHandler);
userDG.dataProvider.removeAll();
}
}
// HANDLE USER SEARCH FAULTS
private function SearchManager_Search_User_Fault(event:FaultEvent):void{
Alert.show("An error occured","Program Error")
}
// USER SEARCH HANDLER
private function userSearchHandler(){
if (firstName.length > 0){
SearchManager_Search_User(firstName.text,lastName.text)
}
else{
SearchManager_Search_User("",lastName.text)
}
}
// EVENT HANDLER FOR ALERT SELECTED OPTION
private function alertClickHandler(event:CloseEvent):void {
if (event.detail==Alert.YES)
showUserDetail()
else
return;
}
//*****************USER SEARCH FUNCTIONs END*******************************
//*************************************************************************
//*****************ADD USER EVENT HANDLER START****************************
// CALL USER ADD COMPONENT
private function showUserDetail():void{
var popUp:userDetail = userDetail(
PopUpManager.createPopUp(this, userDetail, true))
if (userDG.selectedItem){
popUp.uuid.text = userDG.selectedItem.FLD_USERID;
popUp.login.text = userDG.selectedItem.FLD_USERLOGIN;
popUp.pass.text = userDG.selectedItem.FLD_USERPASS;
popUp.firstName.text = userDG.selectedItem.FLD_USERFIRSTNAME;
popUp.lastName.text = userDG.selectedItem.FLD_USERLASTNAME;
popUp.email.text = userDG.selectedItem.FLD_USEREMAIL;
popUp.url.text = userDG.selectedItem.FLD_USERURL;
popUp.sex.selectedIndex = userDG.selectedItem.FLD_USERSEX;
}
else{
return;
}
}
//*****************ADD USER EVENT HANDLER END******************************
Step 4: Creating our User Detail Screen
Now that we have created our user search, we need to create a way for users to add/edit data. This part of the tutorial will not be as defined, since it uses the same practices that we used in the user search steps.
The first thing we need to do is create a new MXML component. Using the same method we used to create our user search screen, create a new mxml component. Instead of choosing the based on selection on panel, choose the based on selection of TileWindow. Give the new component the name userDetail and click finish. You should have the new file userDetail.mxml in your custom folder.
There are a few important notes for the userDetail.mxml file that we will go over.
Step 4a. Validator Models
As with our user search, we need to define a model to validate against. Instead of using a single text input control to validate against we are using five different text input controls. The only thing that separates a multi-validator model from a single validator model is that you need to create a root tag to hold your validators. You can only have a single root tag within a single model. As you can see from the code below, we are using the root tag UserInfo.
<mx:Model id="CheckModel">
<UserInfo>
<UserName>{login.text}</UserName>
<Password>{pass.text}</Password>
<FirstName>{firstName.text}</FirstName>
<LastName>{lastName.text}</LastName>
<Email>{email.text}</Email>
</UserInfo>
</mx:Model>
Step 4b. Multiple Webservice Operations.
The webservice we use for our add/edit user screen has multiple operations within the same Webservice. You do this by defining individual operations like the code below.
<mx:WebService id="UserDetail" useProxy="false" wsdl="com/UserManager.cfc?wsdl"showBusyCursor="true">
<mx:operation name="Add_User"
result="UserDetail_Add_User_Result( UserDetail.Add_User.lastResult )"
fault="UserDetail_Add_User_Fault(event)"/>
<mx:operation name="Edit_User"
result="UserDetail_Edit_User_Result( UserDetail.Edit_User.lastResult )"
fault="UserDetail_Edit_User_Fault(event)"/>
<mx:operation name="Delete_User"
result="UserDetail_Delete_User_Result( UserDetail.Delete_User.lastResult )"
fault="UserDetail_Delete_User_Fault(event)"/>
</mx:WebService>
Step 4c. Application Control Bar
One of the better tags within Flex is the ApplicationControlBar. The ApplicationControlBar container holds components that provide global navigation and application commands. An ApplicationControlBar for an editor, for example, could include Button controls for setting the font weight, a ComboBox control to select the font, and a MenuBar control to select the edit mode. Typically, you place an ApplicationControlBar container at the top of the application.
For our application we will be using the ApplicationControlBar to hold our buttons for Save/Exit/Delete, as you can see below.
<mx:ApplicationControlBar x="0" width="100%" height="35" borderStyle="solid">
<mx:Button label="Save" click="userSaveValidation()" />
<mx:Button label="Exit" click="clearScreen()"/>
<mx:Button label="Delete" click="deleteUserHandler()" />
</mx:ApplicationControlBar>
After completing the reading of this tutorial, I hope that you have a simple understanding of working with Flex and Coldfusion. Undertaking the task of learning a set of new programming languages can be a daunting task, but with the resources available to this fledgling community this task can be enjoyable and educational.
You can get the full source including this tutorial at http://www.easycfm.com/tutorials/tutorial_482/userManager.zip
The fully completed application can be found at http://www.elguapodev.com/tutorials/usermanager/
You can view the flex based source viewer for this project at
http://www.elguapodev.com/tutorials/usermanager/srcview/
I have also included several links to valuable resources for flex below.
http://www.onflex.org/ted/
http://www.ifbin.com/
http://www.cflex.net/
http://groups.yahoo.com/group/flexcoders/
http://www.adobe.com/cfusion/webforums/forum/index.cfm?forumid=60