We help IT Professionals succeed at work.

Form validation problem: cfselect

Eric Bourland
on
1,849 Views
Last Modified: 2012-05-11
ColdFusion 9
MS SQL Server 2005

I have a long form with data input fields of all kinds: text, checkbox, textarea, radio. I would like to get onSubmit validation to work for all input fields.

Currently, onSubmit validation works for all of the text fields in the form. However, I also have eleven different CFSELECT input fields.  When I set an attribute required="yes" for any CFSELECT input field, then onSubmit validation does not work; instead, form validation defaults to onServer validation, and displays the less-than-user-friendly onServer validation error page.

I've been looking around the web for answers to this problem. One solution wanted me to edit CFIDE/scripts/cfform.js:

http://www.barthle.com/blog/post.cfm/cfselect-validation-bug-still-exists-in-cf9

... which I did; however, onSubmit validation still did not work, so I reverted to the original cfform.js file.

Since I have eleven different CFSELECT input fields in this form, it will be problematic to use a javascript to validate each one.

Does anyone have a solution to get onSubmit validation to work for these CFSELECT input fields? As an example, I post below the code for the "State" CFSELECT menu. Thanks as always.

Eric
<!--- default value for form.state --->
 <cfparam name="form.State" default="">
 
 <!--- path to cfform.js is confirmed valid --->
 <cfform method="post" enctype="multipart/form-data" scriptsrc="#Request.CFFORM_JS_LIB#" name="NBPTSForm" id="NBPTSForm">
 
 <!--- other required text fields here .... --->

<!--- this query selects State Titles from tbl_NBPTS_Lookup_State --->
<cfquery datasource="#APPLICATION.dataSource#" name="GetStates">
        SELECT  State_Post_Abbr
        FROM    tbl_NBPTS_Lookup_State
</cfquery>
State: <cfselect size="5" name="State" value="State_Post_Abbr" display="State_Post_Abbr" multiple="no" query="GetStates" queryPosition="below" selected="#getuserDetails.State#" id="State" required="yes" message="Please enter your state of residence." validateAt="onSubmit,onServer">
                <option value=""> Select State: </option>
                </cfselect>  
 
 <!--- submit form .... --->

Open in new window

Comment
Watch Question

Brijesh ChauhanStaff IT Engineer

Commented:
Hey Eric, well there are 2 limitations of CFSELECT validation..

1. required="true" works only for multi-select

2. There is no onValidate for cfselect !!

Here is a workarround code example, hope it helps
<script type="text/javascript">
function validateMyCFSelect() {
if (document.myform.myselect.value != "")
{
   return true;
}
else
{
   alert("You did not make your selection");
   return false;
}
}
</script>

<cfform action="...whatever..."
method="post"
name="myform"
onsubmit="return
validateMyCFSelect()">

<cfselect name="myselect"
size="1"
queryPosition="below"
multiple="no"
required="yes">
<option value="">Please Select<option>
<option value="">Male<option>
<option value="">Female<option>
</cfselect>

Open in new window

Brijesh ChauhanStaff IT Engineer

Commented:
Here is another help, it seems to call the function

_CF_hasValue(obj, obj_type, obj_trim)

so you can have this as well..
<CFFORM... blah blah>
   <CFSELECT name="ThingID" required="Yes" size="1" queryposition="below"
   message="Please make a Thing selection."               value="ThingID" query="qThingTypes" display="Things">
      <OPTION>Please select a Blast Type</OPTION>
   </CFSELECT>
   
   <[SUBMIT]>
</CFFORM>

<SCRIPT>
var _CF_hasValue_old = _CF_hasValue;
_CF_hasValue=function(_b,_c,_d)
{
   if (_b.type == 'select-one')
   {
      var bSelected = false;
      for (var i=0; i<_b.options.length; i++)
      {
         if (_b.options[i].selected == true && _b.options[i].value != '')
         {
            bSelected = true;
            break;
         }
      }
      return bSelected;
   }
   else
      return _CF_hasValue_old(_b,_c,_d);
}
</SCRIPT> 

Open in new window

Author

Commented:
Brij, this is extremely helpful. I will work on this and get back to you tomorrow.

Eric

Author

Commented:
Hey there, Brij,

It looks like ColdFusion replaces the onSubmit function in the CFFORM tag:

<form name="NBPTSForm" id="NBPTSForm" action="/applynow.cfm" method="post" enctype="multipart/form-data" onsubmit="returnvalidateMyCFSelect()">

becomes

<form name="NBPTSForm" id="NBPTSForm" action="/applynow.cfm" method="post" enctype="multipart/form-data" onsubmit="return _CF_checkNBPTSForm(this)">

And, since I have eleven different CFSELECTs to validate, I am not sure that I can put eleven different onSubmit() functions in my CFFORM.

I am not sure how your second suggestion would work, that calls the function _CF_hasValue(obj, obj_type, obj_trim) ?

Thank you again for your help.

Eric
CERTIFIED EXPERT
Most Valuable Expert 2015

Commented:
Since I have eleven different CFSELECT input fields in this form, it will be problematic to use a javascript to validate each one.

Just use onValidate.  Then you can use a single javascript function to validate all of the select lists.

Runnable example
<!--- sample query. for testing ONLY --->
<cfset getStates = queryNew("")>
<cfset queryAddColumn(getStates, "State_Post_Abbr", listToArray("NY,CA,CT"))>

<script type="text/javascript">
	function checkSelect(frm, obj, value) {
		// remove white space 
		var value = value.replace(/\s+/g, "");
		return value.length > 0;
	}
</script>
<cfform>
	<cfselect size="5" name="State1" 
				query="GetStates" 
				value="State_Post_Abbr" 
				display="State_Post_Abbr"
				queryPosition="below" 
				onValidate="checkSelect"
				message="Please enter a State1" 
				validateAt="onSubmit,onServer">
    	<option value=""> Select State: </option>
     </cfselect>  
	<cfselect size="5" name="State2" 
				query="GetStates" 
				value="State_Post_Abbr" 
				display="State_Post_Abbr"
				queryPosition="below" 
				onValidate="checkSelect"
				message="Please enter a State2" 
				validateAt="onSubmit,onServer">
    	<option value=""> Select State: </option>
     </cfselect>  
	
	<input type="submit">
</cfform>

Open in new window


calls the function _CF_hasValue(obj, obj_type, obj_trim) ?

That's an internal function.  It's better not to use those when possible.

Brijesh ChauhanStaff IT Engineer

Commented:
_agx_ you are using onValidate function with CFSELECT, does it work ? I don't see it as a attribute in CFSELECT tag..


http://help.adobe.com/en_US/ColdFusion/9.0/CFMLRef/WSc3ff6d0ea77859461172e0811cbec22c24-7afe.html

Author

Commented:
_agx_ I'll give that a try. E
Brijesh ChauhanStaff IT Engineer

Commented:
@Eric, if onValidate works, then use it.. otherwise I will post an example on how to use _CF_hasValue(obj, obj_type, obj_trim)..

Author

Commented:
brij, sounds good. Thank you. =)
CERTIFIED EXPERT
Most Valuable Expert 2015

Commented:
@bri - Yeah it does work for me w/CF9.  Pretty sure it works w/CF8 too.  Though I'm not positive.

Author

Commented:
A little trouble. If I add these attributes to the CFSELECT tag:

onValidate="checkSelect"
message="Please enter your state of residence"
validateAt="onSubmit,onServer"

... then ColdFusion reverts on onServer validation.

Also, ColdFusion takes this:

<cfselect size="5" name="State" id="State" onValidate="checkSelect" message="Please enter your state of residence" validateAt="onSubmit,onServer">

and reverts it to:

<select name="State" id="State"  size="5"  validateat="onSubmit,onServer" >

stripping away the message and the onValidate attributes.

Question: how do these lines fit in?

<!--- sample query. for testing ONLY --->
<cfset getStates = queryNew("")>
<cfset queryAddColumn(getStates, "State_Post_Abbr", listToArray("NY,CA,CT"))>
<script type="text/javascript">
function checkSelect(frm, obj, value) {
	// remove white space
var value = value.replace(/\s+/g, "");
return value.length > 0; }
</script>

<cfselect size="5" name="State" value="State_Post_Abbr" display="State_Post_Abbr" multiple="no" query="GetStates" queryPosition="below" selected="#getuserDetails.State#" id="State" onValidate="checkSelect" message="Please enter your state of residence" validateAt="onSubmit,onServer">
                <option value=""> Select State: </option>
                </cfselect>

Open in new window

CERTIFIED EXPERT
Most Valuable Expert 2015
Commented:
Unlock this solution and get a sample of our free trial.
(No credit card required)
UNLOCK SOLUTION
CERTIFIED EXPERT
Most Valuable Expert 2015

Commented:
stripping away the message and the onValidate attributes.

I think that's normal when using onValidate.  The validation stuff is added to all the javascript automatically added to the page header section:

ie
...
        //form element State1  custom validation check
        if (!checkSelect(_CF_this, _CF_this['State1'], _CF_this['State1'].value))
        {
            _CF_onError(_CF_this, "State1", _CF_this['State1'].value, "Please enter a State1");
            _CF_error_exists = true;
        }

        //form element State2  custom validation check
        if (!checkSelect(_CF_this, _CF_this['State2'], _CF_this['State2'].value))
        {
            _CF_onError(_CF_this, "State2", _CF_this['State2'].value, "Please enter a State2");
            _CF_error_exists = true;
        }
...

Open in new window


Brijesh ChauhanStaff IT Engineer

Commented:
Hey Eric, here is a solution that works, the problem is that with single select you have the selected index already satisfying the JS condition so that error is not tirggered, so just add

      document.getElementById('select1').selectedIndex = -1; at BOTTOM of your page.. here is a complete working example..

As I suspected ONVALIDATE does not work with CFSELECT..

<cfset selectQuery = queryNew("firstname,id")>

<cfset queryaddrow(selectQuery,1)>
<cfset querysetcell(selectQuery,'firstname','brijesh')>
<cfset querysetcell(selectQuery,'id',1)>
<cfset queryaddrow(selectQuery,1)>
<cfset querysetcell(selectQuery,'firstname','Radhika')>
<cfset querysetcell(selectQuery,'id',2)>
 
<cfform action="" method="post">
	<cfselect name="famlilyid" required="yes" size="1" queryPosition="below" message="Please Make a selection" 
    value="id" query="selectQuery" display="firstname" id="famlilyid">
    </cfselect>
    <input type="submit" name="submit" value="submit">
</cfform>

<script type="text/javascript">
		document.getElementById('famlilyid').selectedIndex = -1;
</script>

Open in new window

Author

Commented:
_agx_,

I use CF9. And I bet the CFSELECT validation does work, in a simpler form. I think there is something else going on with this form.

>>>I think that's normal when using onValidate.  The validation stuff is added to all the javascript automatically added to the page header section:

I understand -- makes sense.

>>> Write a single validation function called on submit that validates all of your lists manually
This might be what I end up doing.

I see new messages from you and and brij -- I will try brij's solution and see what I get.

Thank you both. More soon....

Eric
CERTIFIED EXPERT
Most Valuable Expert 2015

Commented:
the problem is that with single select you have the selected index already satisfying the JS condition

 document.getElementById('select1').selectedIndex = -1;


If he needs to preselect options, I don't think that's the right approach here. Because it would defeat the purpose of his using "selected" ...  

           <cfselect selected="#getuserDetails.State#" ...>

As I suspected ONVALIDATE does not work with CFSELECT..

Not strictly correct.  It's generic javascript that works fine for both of us w/CF9.  I don't know about CF8.  When I get near a CF8 installation I'll have to test it out.
CERTIFIED EXPERT
Most Valuable Expert 2015

Commented:
I think there is something else going on with this form.


That makes more sense ...  Basic logic says if the code works solo (which it does), then the problem must be something else ;-)

Brijesh ChauhanStaff IT Engineer

Commented:
@_agx_, I don't agree with You..

onValidate works for CFINPUT .. and it is mentioned as a attribute in DOCS

http://help.adobe.com/en_US/ColdFusion/9.0/CFMLRef/WSc3ff6d0ea77859461172e0811cbec22c24-7f51.html

but it is NOT mentioned as a attribute for CFSELECT

http://help.adobe.com/en_US/ColdFusion/9.0/CFMLRef/WSc3ff6d0ea77859461172e0811cbec22c24-7f51.html

check the docs, also neither the Dreamweaver not CFBuilder show it as a attribute while adding the tag...
CERTIFIED EXPERT
Most Valuable Expert 2015

Commented:
@brij - We're in agreement about the docs. It's *not* mentioned there.  I'm disagreeing w/your comment that it doesn't work. It DOES work because the CF engine is generating generic javascript deliberately designed to work for most all form fields (since around CF4.5). That's not saying it's the best way to do it. Just that it works.

I'm questioning using selectedIndex=-1 because it would obviously undo Eric's code to pre select an option.



Brijesh ChauhanStaff IT Engineer
Commented:
Unlock this solution and get a sample of our free trial.
(No credit card required)
UNLOCK SOLUTION

Author

Commented:
Now that I think about this -- and per _agx_'s notes -- I don't think I can use:

document.getElementById('select1').selectedIndex = -1;

<cfselect name="famlilyid" required="yes" size="1" queryPosition="below" message="Please Make a selection" value="id" query="selectQuery" display="firstname" id="famlilyid">    </cfselect>

... because if I use that, then the values in the data column, which are already selected, will not appear selected in the Select list. The value of the Selected attribute needs to be: selected="#getuserDetails.State#", as so:

<cfselect size="5" name="State" value="State_Post_Abbr" display="State_Post_Abbr" multiple="no" query="GetStates" queryPosition="below" selected="#getuserDetails.State#" id="State" onValidate="checkSelect" message="Please enter your state of residence" validateAt="onSubmit,onServer">
                <option value=""> Select State: </option>
                </cfselect>

Open in new window


I saw this post in the Forta blog forum that does seem to indicate, at some point, there was no validateAt attribute for CFSELECT:

http://forta.com/blog/index.cfm?mode=entry&entry=A61BB31F-3048-80A9-EFC01CEF006F9775

But I am continuing to research this.

More in a little while... Thank you both again. =)

Author

Commented:
brij, our messages crossed -- I will try your new idea! E
Brijesh ChauhanStaff IT Engineer

Commented:
here is a better example.. hope this helps..
<cfset selectQuery = queryNew("firstname,id")>

<cfset queryaddrow(selectQuery,1)>
<cfset querysetcell(selectQuery,'firstname','brijesh')>
<cfset querysetcell(selectQuery,'id',1)>
<cfset queryaddrow(selectQuery,1)>
<cfset querysetcell(selectQuery,'firstname','Radhika')>
<cfset querysetcell(selectQuery,'id',2)>
 
<cfform action="" method="post">
	<cfselect name="famlilyid" size="1" queryPosition="below" 
    value="id" query="selectQuery" display="firstname">
    <option value="" selected>-Please Select Value -</option>
    </cfselect>
    
    <CFINPUT NAME="dept"
		TYPE="Text"
		STYLE="visibility:hidden"
		BIND="{famlilyid}"
		REQUIRED="Yes"
		MESSAGE="Please Select value">
    <input type="submit" name="submit" value="submit">
</cfform>

Open in new window

CERTIFIED EXPERT
Most Valuable Expert 2015

Commented:
STYLE="visibility:hidden"

Unfortunately CF validation chokes on not visible fields.  Really wish they'd fix that ...
CERTIFIED EXPERT

Commented:
@ eric!

here i found something useful for you!

as per cfml documentation, to make <cfselect>a required field you have to set the value of the default option (the pre-selected option which user has to change) to a signe space string " "
CERTIFIED EXPERT
Most Valuable Expert 2015
Commented:
Unlock this solution and get a sample of our free trial.
(No credit card required)
UNLOCK SOLUTION
CERTIFIED EXPERT

Commented:
check this line

Inside this file, cfform.js modify line #73 this way: [it may differ in cf8, please find the code]
ORIGINAL:
else if (obj_type == "SELECT")
{
for (i=0; i < obj.length; i++)
{
if (obj.options[i].selected)
return true;
}
return false;   
}

MODIFIED:
else if (obj_type == "SELECT")
{
for (i=0; i < obj.length; i++)
{
if (obj.options[i].selected &&
obj.options[i].value != "")
return true;
}
return false;   
}

Open in new window

NOTE: if you use '-1' as your blank option identifier, you'll need to modify the code above to look for that value instead of the empty string. Or you could add both identifiers to catch both number and string values.

You can check this too!

http://www.cfjazz.com/post.cfm/making-cfselect-required-work-for-single-row-select
CERTIFIED EXPERT
Most Valuable Expert 2015

Commented:
as per cfml documentation, to make <cfselect>a required field you have to set the value of the default option (the pre-selected option which user has to change) to a signe space string " "

It still lets you get away with selecting nothing.  ie Select the default option and the form will still submit.  

      <option value="(space)"> Select State: </option>
Brijesh ChauhanStaff IT Engineer

Commented:

@_agx_ >>Unfortunately CF validation chokes on not visible fields.

Please try the  example code, it works correctly....
CERTIFIED EXPERT

Commented:
@eric, He can still modify the function which is inside the cfform,js where the selected index is used and add additional values over there, that might help him

Author

Commented:
It looks like _agx_'s code in ID: 35427195 is working.... I am testing it further.

I will also try out brij's solution ... I would just like to see if it works.

More in a minute.

Randhawa ... yep, I saw that modification of cffrom.js, and I even tried it out! It did not seem to have any effect for me.
CERTIFIED EXPERT
Most Valuable Expert 2015

Commented:
@brij - Which one? I tried one of them w/Eric's cfselect (size=5) and IE complained about setting focus on invisible fields.

CERTIFIED EXPERT

Commented:
Hi Eric, In your above main post you have CF9, So i expect you are using CF9's CFForm.js File

Check for this Code
if(_c=="SELECT"){
for(i=0;i<_b.length;i++){
if(_b.options[i].selected&&_b.options[i].value.length>0){
return true;
}
Change it to
if(_c=="SELECT"){
for(i=0;i<_b.length;i++){
if(_b.options[i].selected&&_b.options[i].value.length>0&&_b.options[i].value != ""){
return true;
}

Open in new window

Brijesh ChauhanStaff IT Engineer

Commented:
<cfset selectQuery = queryNew("firstname,id")>

<cfset queryaddrow(selectQuery,1)>
<cfset querysetcell(selectQuery,'firstname','brijesh')>
<cfset querysetcell(selectQuery,'id',1)>
<cfset queryaddrow(selectQuery,1)>
<cfset querysetcell(selectQuery,'firstname','Radhika')>
<cfset querysetcell(selectQuery,'id',2)>
 
<cfform action="" method="post">
	<cfselect name="famlilyid" size="1" queryPosition="below" 
    value="id" query="selectQuery" display="firstname">
    <option value="" selected>-Please Select Value -</option>
    </cfselect>
    
    <CFINPUT NAME="dept"
		TYPE="Text"
		STYLE="visibility:hidden"
		BIND="{famlilyid}"
		REQUIRED="Yes"
		MESSAGE="Please Select value">
    <input type="submit" name="submit" value="submit">
</cfform>

Open in new window

CERTIFIED EXPERT
Most Valuable Expert 2015

Commented:
It did not seem to have any effect for me.

Maybe it's cached or needs to be tweaked for CF9? I didn't test it, .. but I've used something like what myselfrandhawa posted before .. and can confirm it does work :)
CERTIFIED EXPERT

Commented:
Can you use jquery in this! let me know
Brijesh ChauhanStaff IT Engineer

Commented:
@Eric, the above post, I checked it on IE and FF, works good...

if _@agx_ solution works, then go ahead and use it..
Brijesh ChauhanStaff IT Engineer

Commented:
ahhh.. so many comments.. @eric, commentid 35427352
CERTIFIED EXPERT
Commented:
Unlock this solution and get a sample of our free trial.
(No credit card required)
UNLOCK SOLUTION

Author

Commented:
I'm gonna use _agx_'s code in ID: 35427195.

I will need to enter a separate function for each select menu, for example:

function validateStateSelect(frm, obj, value)
function validateSexSelect(frm, obj, value)
function validateRaceSelect(frm, obj, value)

I can live with that. This solution integrates with the existing CF9 form validation.

I am going to implement and test this for a while, then I'll come back here with results.

Thank you friends as always,

Eric
CERTIFIED EXPERT
Most Valuable Expert 2015
Commented:
Unlock this solution and get a sample of our free trial.
(No credit card required)
UNLOCK SOLUTION
CERTIFIED EXPERT

Commented:
@ Eric! Go ahead and try whichever suits your need!

Do also test this one also!

@ ID35427343
CERTIFIED EXPERT
Most Valuable Expert 2015
Commented:
Unlock this solution and get a sample of our free trial.
(No credit card required)
UNLOCK SOLUTION
Brijesh ChauhanStaff IT Engineer

Commented:
>> Nope. I really like the bind idea, but IE8 barfs on the invisible fields, it works for me on IE 9, may be time for everyone to upgrade :-)
CERTIFIED EXPERT

Commented:
whole microst is absurd, there no ie has any stable version, everyone ie versoion runs with different coinfigrastions of its own..

:)
CERTIFIED EXPERT
Most Valuable Expert 2015
Commented:
Unlock this solution and get a sample of our free trial.
(No credit card required)
UNLOCK SOLUTION

Author

Commented:
>>>Just give the hidden fields the same name as the cfselect's followed by an underscore "_" and a suffix like "Validate" and it'll work fine.

Got it. It's working really well.
CERTIFIED EXPERT
Most Valuable Expert 2015

Commented:
@brij - Lol.  When you find a way to run multiple versions of IE *reliably*, let me know ;-)

Author

Commented:
Thank you as always to _agx_, brij, and randhawa.
Unlock the solution to this question.
Thanks for using Experts Exchange.

Please provide your email to receive a sample view!

*This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

OR

Please enter a first name

Please enter a last name

8+ characters (letters, numbers, and a symbol)

By clicking, you agree to the Terms of Use and Privacy Policy.