So, I'm working on a CFFORM application now to process donation requests. This used to be a 5 step process over a bunch of JSP files. It is now being rewritten for ColdFusion MX 7. I set up the form to use the accordion style. After some initial hurdles (see my others posts), I had something I was proud to show off. Instead of 5 different pages, I now had one simple (and pretty) Flash based form.
Then my boss checked it out and asked why he could go from one accordion to another when the fields weren't correct. I pointed out that the validation would fire at the end of the process, but he said this wasn't very intuitive. I agreed - and began to deep. After talking with Nimer, he pointed me to the following piece of code:
onClick="mx.controls.Alert.show(mx.validators.Validator.isStructureValid(this,'form1'))"
This litte piece of code will fire the a function, isStructureValid, that will check the entire form. This was close - but not what I needed. I dug around the ActionScript documentation for Flex until I found: mx.validators.Validator.isValid(a,b). This will check one particular field to see if it is ok.
So - I know how to check particular fields. I could then add a Next button to my accordion page so that when you clicked on it, I checked the fields for that page. It wasn't automatic - but it worked.
My next step was to design a UDF to spit out the ActionScript code for me. With that in mind, I present checkFieldSet:
<cfargument name="fields" type="string" required="true" hint="Fields to search">
<cfargument name="form" type="string" required="true" hint="Name of the form">
<cfargument name="ascode" type="string" required="true" hint="Code to fire if all is good.">
<cfargument name="message" type="string" required="false"
default="You have not completed one or more of the items on this page.\nPlease correct the items in red."
hint="Message to display on error.">
<cfset var vcode = "">
<cfset var f = "">
<cfsavecontent variable="vcode">
var ok = true;
<cfloop index="f" list="#arguments.fields#">
<cfoutput>
if(!mx.validators.Validator.isValid(this, 'donations.#f#')) { if(ok) mx.controls.Alert.show('#arguments.message#'); ok = false;};
</cfoutput>
</cfloop>
</cfsavecontent>
<cfset vcode = vcode & "if(ok) #ascode#">
<cfset vcode = replaceList(vcode,"#chr(10)#,#chr(13)#,#chr(9)#",",,")>
<cfreturn vcode>
</cffunction>
The UDF works pretty simply. You pass it the name of the fields you want to check. Then you tell it the name of the form. I'll be honest here - I'm not sure this is 100% required. More on that later though. Next, you pass in the ActionScript code you want to fire if all the fields pass their validation. Lastly - there is an optional argument that lets you specify the message to display. As you can see, this is a nice and vague message since we can't get the real message for each "bad" field. Actually, I prefer this message. When the isValid fires, it will mark the bad fields anyway, so the message simply tells the user what to look for.
Here is an example of how to use it:
So - the ActionScript. I'm sure I could have written it better. All I know is that it works. :) So feel free to suggest something a bit tighter.
Archived Comments
Looks pretty tight to me Ray... welcome to AS. Now, I got to dive into this cfmx 7.
When using the accordion or tab navigator, do you know of a way to tell which cfformgroup page was front most when the submit button was clicked? I'm trying to use a 3-tab search form, each distinct, but all form fields come across. The user could enter a field value on one tab, switch to another tab and enter value in another field, then click search. I'd want to do the search based on which one was front most, not which had field content, because they both would.
I believe there is a "enabled" property. If you give each tag/accordian a name, you may be able to check each one. I'll try this tomorrow (swamped today) and if I find it, I'll blog it in a new entry.
Although - do you have a button on each tab/accordiaon? If so, why not give them the same name, but different values?
I only had one search button for the entire form, underneath the tab navigator. I have changed this to separate submit buttons on each tab, with unique names, and can differentiate in the code which one was clicked. So I can use this. Would still be nice to know which was front-most though. Thanks.
just a little enhancement to Ray's nice little checkFields function..
change these lines to this:
old:
<cfoutput>
if(!mx.validators.Validator.isValid(this, 'donations.#f#')) { if(ok) mx.controls.Alert.show('#arguments.message#'); ok = false;};
</cfoutput>
new:
<cfoutput>
if(!mx.validators.Validator.isValid(this, '#arguments.form#.#f#')) { if(ok) mx.controls.Alert.show(#f#.errorString,"Errors"); ok = false;};
</cfoutput>
first #arguments.form# (instead of the static 'donation' form) should have been there in the first place. but what (#f#.errorString,"Error") does is this.. it give the Alert window a title "Error" and it uses the cfinput messsage="" attribute to display in the message part of the Alert window (instead of that generic 'You have missed some items in red...').
What I want to do next is customize the styling on this Alert window (font-family , font-size, color, etc.) , but I'm having some problems with that a the moment. Any help is appreciated. And I will post the new function if I figure it out.
Thanks Ray,
Brett
Forgot to Subscribe. That's all I'm doing on this post.
The donations part was definitely a screw up - a hold over from the original code. Thanks! So you are saying I -can- get the original msg for the bad form field? I thought that was impossible. Awesome. I'll update it later tonight.
yeah, in ActionScript myfieldname.errorString holds the cfinput message attribute.
hey, can you submit a form using ActionScript? like the equivalent to formname.submit() in JavaScript.
I thought it was myformname.submitForm() , but it didn't work.
I tried the modification to show the particular error msg for a field and it did not work. This is the line code I have:
if(!mx.validators.Validator.isValid(this, '#arguments.form#.#f#')) { if(ok) mx.controls.Alert.show(#f#.errorString,'Error'); ok = false;};
Oops. Typo on my part. It works. Now - here is my problem. While I like getting the specific message - I don't like the fact that it is just the _first_ error. I think the error msg I had - eventhough vague - told you to check the entire page for errors. Know what I mean? I wonder if I should simply take all the errors and concate them together.
Yeah, that would very nice. The only thing that might be a problem there is the amount of field errors. What if there is 20 (or more) fields to concat? Is that going to look weird?
But yeah, if its only a few field errors (which is probably the norm anyway) that would be very good.
This flash stuff is nice but man there's a lot to learn on the ActionScript side. And the Macromedia documentation for the Object Model is lacking. I need some better documentation. Any ideas?
Brett - when I ran it and a lot of errors showed up - the Alert box actually had a scrol component! I think it worked fairly well.
Hey - are you related to Matt Liotta?
Really, that's pretty cool. You can probably also adjust the height and width of the Alert box. But a scroll works as well.
No I don't think I know a Matt Liotta. I do know a Ray Liotta though. Ever hearda him?
Hello Ray and Brett,
Well I tried your checkFields codes but somehow I cannot make it to show all of the errors.
When I ran it, I get two alert boxes on top of each other: one with empty message and the other with the values in the message="" attribute
of the second required field control. Where am i messing it up?
Here is my entired code:
<cffunction name="checkFieldSet" output="false" returnType="string">
<cfargument name="fields" type="string" required="true" hint="Fields to search">
<cfargument name="form" type="string" required="true" hint="Name of the form">
<cfargument name="ascode" type="string" required="true" hint="Code to fire if all is good.">
<cfset var vcode = "">
<cfset var f = "">
<cfsavecontent variable="vcode">
var ok = true;
var msg = "";
<cfloop index="f" list="#arguments.fields#">
<cfoutput>
if(!mx.validators.Validator.isValid(this, '#arguments.form#.#f#')) { if(ok) mx.controls.Alert.show(#f#.errorString,"Errors"); ok = false;};
</cfoutput>
</cfloop>
</cfsavecontent>
<cfset vcode = vcode & "if(!ok) mx.controls.Alert.show(msg,'Error'); ">
<cfset vcode = vcode & "if(ok) #ascode#">
<cfset vcode = replaceList(vcode,"#chr(10)#,#chr(13)#,#chr(9)#",",,")>
<cfreturn vcode>
</cffunction>
<cfform name="form1" format="flash" skin="haloblue" width="580" height="500" action="index.cfm" preservedata="yes">
<cfformgroup type="page">
<cfinput name="InsuranceName" type="text" label="Insurance Company Name:" width="150" required="yes" message="InsuranceName is Required." />
<cfinput name="PlanType" type="text" label="Plan Type:" width="150" required="yes" message="PlanType is Required." />
<cfinput name="PolicyNumber" type="text" label="Policy Number:" width="150" required="yes" message="PolicyNumber is Required." />
<cfinput name="GroupName" type="text" label="Group Name:" width="150" required="yes" message="GroupName is Required." />
<cfinput name="GroupNumber" type="text" label="Group Number:" width="150" required="yes" message="GroupNumber is Required." />
<cfinput name="Display" type="text" label="Display:" width="150" />
</cfformgroup>
<cfinput type="button" name="step3b" value="Next" onClick="#checkFieldSet("PlanType,PolicyNumber,GroupName,GroupNumber","form1","PlanType.text=InsuranceName.text")#">
</cfform>
Thanks to both of your creation!
Sakang,
On first glance, I'm not seeing the "msg" variable being set to anything. And, there are two places you are calling the Alert so that would explain the two pop ups. And you can play with that new "buttonWidth" line. I used that b/c the error message was wrapping funny.
Check this (all I changed was the function):
<cffunction name="checkFieldSet" output="false" returnType="string">
<cfargument name="fields" type="string" required="true" hint="Fields to search">
<cfargument name="form" type="string" required="true" hint="Name of the form">
<cfargument name="ascode" type="string" required="true" hint="Code to fire if all is good.">
<cfset var vcode = "">
<cfset var f = "">
<cfsavecontent variable="vcode">
var ok = true;
var msg = "";
<cfloop index="f" list="#arguments.fields#">
<cfoutput>
if(!mx.validators.Validator.isValid(this, '#arguments.form#.#f#')) { msg += #f#.errorString + "\n"; ok = false; }
</cfoutput>
</cfloop>
</cfsavecontent>
<cfset vcode = vcode & "if(!ok) { mx.controls.Alert.buttonWidth=100; mx.controls.Alert.show(msg,'Error'); }">
<cfset vcode = vcode & "if(ok) #ascode#">
<cfset vcode = replaceList(vcode,"#chr(10)#,#chr(13)#,#chr(9)#",",,")>
<cfreturn vcode>
</cffunction>
Let me re-word that first section before the code b/c upon reading it didn't make sense.
On first glance, I'm not seeing the "msg" variable being set to anything. And, there are two places you are calling the Alert so that would explain the two pop ups.
(All I changed was the function. You can play with that new "buttonWidth" line. It controls the width of the Alert in pixels. I used that b/c the error message was wrapping funny.)
This is pretty much the closest thread that I've found for what I'm trying to do. Does anyone know if there is a simple way that you can get the client side validation to fire if you're using a type="button" instead of type="submit"?
Basically, I'm using flash remoting and dont' want the the form to actually submit to itself or any other page, causing the page to reload. My AS validates the required fields (they turn red and the little baloons show up, etc, but the alert box doesn't pop up for me using this method).
<cfinput type="button" onClick="submitForm()" value="Submit Data">
Does anyone know a way that I can have the default validation alert message pop up using this method?
I'm using CFForm which has multiple tabs (I am using cfformgroup type=tabnavigator), how would I validate if the user switches from one tab to another? Does anyone have any idea how to validate?
Thanks,
Magesh.R
This is loosely related to the topic in that it is involving a flash <cfform> question I was asked recently. The issue was that the default error alert on a required field was showing further down on the form due to the size of the form. It's a long form and middle can be below the fold. They wanted to know if there was any way to move the alert popup to the top of the form so it was more prominent. I havent found a way so thought i'd take a shot here since flash CFForms are being discussed.