Login System For A Flex Application With ColdFusion Backend Part 4 - Validation and Error Message
Introduction to Part 4 - Validation and Error Message
At the end of part 3, I had a working Login Form component. I next need to handle what would happen if the user inputted an incorrect user name and/or password. My CFC throws an error (see parts 1 and 2) if the user name and password cannot be found in the table. So I have several choices on how to handle the error returned by the CFC to my Flex application.
I could show the event.fault.faultString (which will contain the message the CFC error returned) in an Alert popup or I could just add an error notice to the login form. I decided to implement the later. Additionally, in this part of the design I added some validation to the two input boxes in the login form.
You can view this version of the Flex login application and right click on it to view the source code. All the changes made for part 4 are in the LoginForm.mxml custom component. The correct username is phil1021 and the password is seven.
Communicating Errors Between The CFC and Flex
If you examine the MemberService.cfc function getMemberByUserNameAndPassword, you'll notice that this function may throw an error (exception) if the query results contain no records, more than one record, or if the query does not execute successfully.
<cfquery name="getMember" datasource="#variables.dsn#">
select memID, memUserName, memPassword, memFirstName, memLastName, memEmail
from member
where memUsername = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.aUserName#">
and memPassword = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.aPassword#">
</cfquery>
<!---throw error if no records were found--->
<cfif getMember.recordCount EQ 0>
<cfthrow type="Member.NoRecordsFound" message="No members with with username of #arguments.aUserName# and password of #arguments.aPassword# were found">
</cfif>
<!---throw error if more than one record was found, violates business rule--->
<cfif getMember.recordCount GT 1>
<cfthrow type="Member.TooManyFound" message="Too many members with username of #arguments.aUserName# and password of #arguments.aPassword# were found" />
</cfif>
<cfcatch type="database"> <!---there was a problem with a query--->
<cfthrow type="Member.select" message="#cfcatch.detail#" />
</cfcatch>
</cftry>
If this CFC function does throw an error, my Flex application will call the function I specified to handle the fault when I created the RemoteObject.
id="MemberService"
destination="ColdFusion"
source="brucephillips.GeekNews.MemberService"
showBusyCursor="true"
>
<mx:method name="getMemberByUserNameAndPassword"
result="resultGetMemberByUserNameAndPassword(event)"
fault="faultGetMemberByUserNameAndPassword(event)"/>
</mx:RemoteObject>
Passed to that function is the event object. The event object will contain details about the error. In event.fault.faultString will be the string I assigned to the message attribute of the cfthrow tag in the CFC function. So I could easily display the error message in my Flex application using an Alert popup box. I could also use some logic within my fault function in the LoginForm component to execute different tasks depending on the error message. For example, if the error message included text about a database problem (perhaps my database server is down), I could show a different error message to the user and also call a CFC function to email the database administrator.
To keep my LoginForm simple, I decided just to show the user a short error message in the LoginForm if the CFC function returns an error. To show the error message I changed the state of the LoginForm. For an introduction to the mx:states tag see this article I wrote (the article includes some references to learn more about mx:states).
automatically called if the CFC method call causes an error
*/
private function faultGetMemberByUserNameAndPassword(event:FaultEvent):void{
//Alert.show( ObjectUtil.toString(event.fault) );
//Alert.show(event.fault.faultString );
currentState = 'loginError';
}//end function faultGetMemberByUserNameAndPassword
In the above function, I just change the state of the LoginForm to the loginError state. That state is defined below.
<mx:states>
<!--define what needs to be added/removed when showing the loginError
state-->
<mx:State name="loginError" id="loginError">
<!-- add some additional form elements to the login form-->
<mx:AddChild relativeTo="{this}" position="firstChild" creationPolicy="all">
<mx:FormItem id="errorMsg">
<mx:Text text="ERROR! User name or password not correct!" color="red" fontSize="14" width="200" />
</mx:FormItem>
</mx:AddChild>
</mx:State>
</mx:states>
Note the value of the relativeTo attribute for the mx:AddChild tag. I want to add the error message to this application. Also, when the login is successful, I need to ensure that I set the state of the LoginForm to its default state so that the loginError state is not show again when the user logs out.
Validating User Input
My LoginForm component already had some simple validation. The login button will not be enabled unless the user has entered text into both the username and password input boxes. However, in this iteration of the design, I added two String validators to limit how much text the user can type into the two input boxes (see the maxLength attribute of the mx:StringValidator tag. For a quick introduction to validators visit this previous blog entry.
Coming Next
In the next iteration, I'll work on satisfying the second use case I specified at the beginning of the design process:
B. User visits the application and the login screen loads. User is not already a member. User clicks on the join button. Login form changes to a registration form. User enters registration information correctly. User's information is stored in the database successfully. Registration form changes back to login form. User proceeds as in case A.
There are no comments for this entry.
[Add Comment]