Coldfusion Server Side Validation Sometimes Required sometimes not depending on radio buttons - coldfusion

I am trying to get a better understanding of server side validation. I have been writing a lot of client side validation using JavaScript but did not realize if the user just turns JavaScript off the whole app does not validate any field. This is what I am looking into doing for ColdFusion Server side validation.
What I am wondering is how would you toggle on and off making a field required or not based on lets say a radio buttons yes or no. Say you have a radio button the if yes is chosen it makes another input required but if no is chosen it makes another field required. I was just wondering how you would do something like that with the _cf format of toggling on and off. Would you just create if statements on hidden fields to do so or something?
I have been researching it a lot and just was looking for some input on how people are achieving things like this because it just seems like you can do so much through client side but then its all pointless because they can just turn it off.
<table>
<tr>
<td>Date:</td>
<td><input type="text" name="date" size="20"></td>
<strong class="delete me and add my line number to the highlight in my pre tag">
<input type="hidden" name="date_cfformrequired" value="You must enter a date.">
<input type="hidden" name="date_cfformdate" value="The date you entered is not a valid date."></strong>
</tr>
<tr>
<td>Distance:</td>
<td><input type="text" name="distance" size="20"></td>
<strong class="delete me and add my line number to the highlight in my pre tag">
<input type="hidden" name="distance_cfformrequired" value="You must enter a distance.">
<input type="hidden" name="distance_cfformfloat" value="The distance you entered is not a valid number."></strong>
</tr>
<tr>
<td>Time:</td>
<td><input type="text" name="time" size="20"></td>
<strong class="delete me and add my line number to the highlight in my pre tag">
<input type="hidden" name="time_cfformrequired" value="You must enter a time.">
<input type="hidden" name="time_cfformregex" value="^\d{1,3}:\d{0,2}$"></strong>
</tr>
<tr>
<td>Comments:</td>
<td><input type="text" name="comments" size="50"></td>
<strong class="delete me and add my line number to the highlight in my pre tag">
<input type="hidden" name="comments_cfformrequired" value="You must enter a comment.">
<input type="hidden" name="comments_cfformmaxlength" value="50"></strong>
</tr>
<tr>
<td colspan="2" align="right">
<input type="submit" name="Add Entry">
</td>
</tr>
</table>

Your understanding of the difference between client and server side validation is correct. Consider that client side validation can be chalked up to a feature. Rather than the user entering information, submitting the form, and then being told something was incorrect, Javascript validation can guide them, but because it can be disabled, it's not good to rely on.
Server side validation always happens as dictated.
The code is pretty easy
As an example - HTML
Name:
<input type="text" name="myname">
Were you referred by a current user?
<input type="radio" name="Referred" value="0" checked> No
<input type="radio" name="Referred" value="1"> Yes
Who referred you?
<input type="text" name="ref_user">
Form processing
<cfset Err = {Messages = []}> // creates a struct named Err with an array names Messages.
<cfif len(trim(form.myname)) eq 0>
<cfset ArrayAppend(Err.Messages,"Please enter your name!">
</cfif>
<cfif form.Referred eq 1 and len(trim(form.ref_user)) eq 0>
<cfset ArrayAppend(Err.Messages,"You said someone referred you, who was it?">
</cfif>
<cfif ArrayLen(err.messages) eq 0>
...no errors, we can do form processing...
</cfif>
And then, when outputting your errors, if they exist
<cfif ArrayLen(err.messages) gt 0>
Sorry, an error occurred.<br>
<cfoutput>
<cfloop array="#err.messages#" index="cError">
- #cError#.<br>
</cfloop>
</cfoutput>
</cfif>
On the first line of the last code snippet, you'll see gt 0 at the end of the line. This is not necessary and most people will leave it off. You seem familiar with javascript, cf works the same way in that in that you might say
if (Err.Messages.length) {
... show
}
In cf, you can do similar, <cfif ArrayLen(Err.Messages)>.
Remember to either cfparam your variables or check for their existence in your form processing, like this..
<cfif not StructKeyExists(form, "Referred") or (form.Referred eq 1 and len(trim(form.ref_user)) eq 0)>
<cfset ArrayAppend(Err.Messages,"You said someone referred you, who was it?">
</cfif>

Related

How do I process data in a list in cold fusion 10

I have a form that has 3 rows. A checkbox and two input field per row.
The field names are paid, amount and tranid.
If I tick the checkbox on the second row, and enter data into the other two fields and click submit I have the following;
Listlen is 1.
listgetat(form.paid,1) contains the value assigned to the check box.
the list for amount are 0.00,16.00,0.00
The list for tranid id are "",Test123,"" (nul, value, nul)
Therein is my problem. I can't loop through the list because listlen = 1 and listgetat(form.amount,1) returns 0.00 because the data is in the second list item.
I can't get the value from listgetat(form.paid,2) because I only selected one checkbox, so listgetat(form.paid,1) contains that value.
Clearly my understanding of working with lists is lacking.
This is a payment processing page, where the user selects which outstanding payments have been paid. They enter a bank transaction ID and how much was paid. The number of rows depends on how many payments are outstanding, in this test case there are three.
Can someone please explain how to process the list.
thank you.
The input page; Select only unpaid transactions:
<cfquery name="unpaid" datasource="#Application.datasource#">
select * from payments where pflag=0
</cfquery>
The input page; The three relevant fields;
<cfif #unpaid.recordcount# gt 0>
<cfoutput query="unpaid">
<tr>
<td><span class="pagetext">
<input type="checkbox" name="paid" id="paid" value="#idpayments#" />
</span></td>
<td class="pagetext">#idpayments#</td>
<input name="tranid" type="text" id="tranid" size="15" maxlength="40" /></td>
<td align="right">
<span class="pagetext">$<input name="amount" type="text" id="amount" size="7" maxlength="7" value="#ap#" />
</span></td>
</tr>
<cfset total=#total#+#ep#>
</cfoutput>
</cfif>
The processing code..
<cfloop from="1" to="#Listlen(FORM.amount)#" index="i">
<cfif #ListGetAt(FORM.amount,i)# gt 0>
<!--- update the payment --->
<cfquery name="updtrec" datasource="#Application.datasource#">
update payments set pflag=1,
ap=#ListGetAt(FORM.amount,i)#,
datepaid='#newdate#',
<cfif #len(ListGetAt(FORM.tranid,i))# gt 0>, ptranid=#ListGetAt(FORM.tranid,i)#</cfif>
where idpayments=#ListGetAt(FORM.paid,i)#
</cfquery>
</cfif>
</cfloop>
A description of the issue is helpful, but you should also include some code along with it. The absolute smallest amount of code needed to illustrate the issue, omitting any irrelevant stuff like css. Here's a good example for this question:
<form ...>
Row #1
<input type="checkbox" name="paid" value="111">
Amount <input type="text" name="amount">
TransId <input type="text" name="transid">
<br>
Row #2
<input type="checkbox" name="paid" value="222">
Amount <input type="text" name="amount">
TransId <input type="text" name="transid">
<br>
Row #3
<input type="checkbox" name="paid" value="333">
Amount <input type="text" name="amount">
TransId <input type="text" name="transid">
</form>
Clearly my understanding of working with lists is lacking.
The problem isn't your understanding of lists, but of how form fields are handled. The code mistakenly assumes all three form variables will always contain a list of three values. They won't. While same name'd fields get converted into a comma separated list when submitted, not all form fields submit a value and some values are effectively discarded:
A checkbox only submits a value IF it's checked
An enabled text field always submits a value, but that value may be an empty string. Historically, most list functionality in CF ignores empty strings
So the form variables aren't guaranteed to always contain a list of three values. It may be less if some of the text fields are empty or boxes aren't checked (form.paid won't even exist at all if none of the boxes are checked). That's why the list functions aren't working as you expected.
Assuming you have a unique numeric value like an "id" for each row, give all checkboxes the same name and use the numeric id as the checkbox value. Then use the numeric "id" as part of the associated text field names, in order to group each row of fields together
<input type="checkbox" name="paid" value="111">
<input type="text" name="amount_111">
<input type="text" name="transid_111">
...
<input type="checkbox" name="paid" value="222">
<input type="text" name="amount_222">
<input type="text" name="transid_222">
...
When submitted, form.paid will contain a list of the selected id's. Loop through the list of id's and use the current "id" to extract the amount and transid values:
for (....) {
amount = form["amount_"& currentId];
transid = form["transid_"& currentId];
}

How can I keep form values without using session?

I have one form page with pagination. I want to keep the form values as the user goes to the previous or next page, using pagination. I know that it can be done using the session scope. However, here I don't want to use session scope. Does anyone have any ideas on how to do this without using session? Please let me know.
Here is my form page:
<cfoutput>
<form action="#buildUrl(action='survey.save_surveyresults',querystring='surveyId=#rc.surveyid#')#" method="post">
<input type="hidden" name="id" value="0">
<input type="hidden" name="surveyid" value="#rc.surveyId#">
<div class="container-fluid">
<div class="row">
<div class="control-group">
<label class="label-control" for="name">Name</label>
<div class="controls">
<input type="text" name="name" id="name" required="true" placeholder="enter your name" value="#rc.name#">
</div>
</div>
<div class="control-group">
<label class="label-control" for="email">Email</label>
<div class="controls">
<input type="text" name="email" id="email" required="true" placeholder="enter your Email" value="#rc.email#">
</div>
</div>
<cfloop query="rc.questions" startrow="#startrow#" maxrows="#perpage#">
<!--- because we have all questions and answers in query we can use switch instead calling template or view
for each question, so its simplify directory structures, questions directory is not necessary now --->
<h3>#CurrentRow#<cfif rc.questions.isrequired><strong>*</strong></cfif>. #rc.questions.question#<h3>
<cfswitch expression="#rc.questions.template#">
<fieldset>
<cfcase value="textbox">
<input type="text" class="input-xlarge" name="#template#_#questionid#" id="question_#questionid#">
</cfcase>
<cfcase value="multiplechoice">
<cfloop list="#answer#" delimiters="," index="i">
<div class="controls">
<label>
<input type="radio" name="#template#_#questionid#" id="question_#questionid#" value="#answerID#" >
<span class="lbl">#i#</span>
</label>
</div>
</cfloop>
</cfcase>
<cfcase value="multiplechoiceother">
<cfloop list="#answer#" delimiters="," index="i">
<div class="controls">
<label>
<input type="radio" name="#template#_#questionid#" id="question_#questionid#" value="#answerID#" >
<span class="lbl">#i#</span>
</label>
</div>
</cfloop>
<div class="control-group">
<label class="label-control" for="other">Other</label>
<div class="controls">
<input type="text" class="input-xlarge" name="#template#_#questionid#" id="question_#questionid#">
</div>
</div>
</cfcase>
</fieldset>
</cfswitch>
</cfloop>
<p></p><br />
<cfif startrow GT 1>
Previous
</cfif>
<cfif (startrow + perpage - 1) lt rc.questions.recordcount>
Next
<cfelse>
<button type="submit" name="submit" class="btn btn-success">Finish</button>
</cfif>
</div>
</div>
</div>
</form>
</cfoutput>
You could break the form up into different sections and have it all in one page. You can hide/show parts of the form using JavaScript based on which 'page' of the form they are one.
This makes going forward or backward in the form a snap since it is not submitted until they are done with the whole form and the values they entered will still be there.. and is pretty easy to handle with jQuery or other JavaScript libraries.
As Dan said - save submitted values in hidden fields.
One issue I see with your HTML is that Previous/Next pages are just links - not submit buttons. So make sure that when clicking those links users are submitting the form - not just going to a different url.
Here's a simple snippet of code that will embed all your form variables into hidden fields. You would place this code inside the form handler on the page you are submitting to. Note Lucas' answer as well. Your form may not be submitting correctly for reasons of badly formed..er...form.
<Cfloop collection="#form#" item="fItem">
<cfoutput>
<input type="hidden" name="#fItem#" value="#form[fItem]#"/>
</cfoutput>
</cfloop>
Again .. this would go _inside" of the form on the subsequent page. This is fairly common in multipart forms (shopping carts with multiple steps, profile entries etc).
Bear in mind that with the approaches above, you need to re-validate your form values on the server side every time you submit them (or at the very least before your final processing).
What you make up for in server memory, you may lose in terms of traffic and load times, depending on scale so I would advise that you proceed with caution. Increasing production traffic unnecessarily can result in financial impacts, and often server memory can be cheaper than extended increased traffic outlay; it comes down to your requirements and scale at the end of the day.
Shipping form variables around also increases your attack surface for malicious injection of form data, so while you may be concerned with session variables being altered on you (curious to hear more on this), you are already opening yourself up by shipping this data around as plain text. Do not rely on client-side validation for this (or any) data.

CFINPUT required="yes" not working with CFLOOP

When I click Submit button (no data was entered) the text boxes were empty and it still goes to the next page without popping up any messsage. It seems the cfinput required="yes" does not work the cfloop. I thought it should work even with the cfloop. I could not find what was wrong. How can I make it work? any info is greatly appreciated. Thank you.
<cfform name="theForm" action="nextPage.cfm" method="post">
<table>
<tr>
<td><cfinput type="text" name="A" size="50" required="yes message="please enter your text"></td>
</tr>
<td><cfinput type="text" name="B" size="50" required="yes message="please enter your text"></td>
</tr>
<cfloop from=1 to=5 index=i>
</tr>
<td><cfinput type="text" name="C" size="50" required="yes message="please enter your text"></td>
</tr>
</tr>
<td><cfinput type="text" name="D" size="50" required="yes message="please enter your text"></td>
</tr>
</cfloop>
<tr>
<td><cfinput type="submit" name="Submit" value="Submit"></td>
</tr>
</table>
</cfform>
For this to work, you need to have unique NAMEs for each input field. Right now, you're creating a bunch of inputs named either "C" or "D". If any one "C" is filled in, then no other field named "C" needs to be filled in. Create unique names using your index variable and the validation should work as you intend.
<cfloop from=1 to=5 index=i>
</tr>
<td><cfinput type="text" name="C_#i#" size="50" required="yes message="please enter your text"></td>
</tr>
</tr>
<td><cfinput type="text" name="D_#i#" size="50" required="yes message="please enter your text"></td>
</tr>
</cfloop>
There is a syntax error in the cfinput tag
It should be
<cfinput type="text" name="D" size="50" required="yes" message="please enter your text">
There is a missing quote after yes
In addition to what was said you should use something else and not cfform if you want anything more than basic validation. The cfform stuff is really legacy and there are much better options these days.

displaying questions twice

can anyone review this code tell me what's wrong in it? I don't understand why it is displaying questions two times.
here is the code to display questions based on its questiontype, I mean it will look into question folder for matching questiontype template and then display it with question.
this is the code to show survey's questions.
<cfoutput>
<cfset step = 0 />
<form class="form form-horizontal" action="#buildUrl(action='survey.savesurveyresults',querystring='surveyId=#rc.surveyid#')#" method="post">
<input type="hidden" name="id" value="0">
<input type="hidden" name="fksurveyid" value="#rc.surveyId#">
<input type="hidden" name="fkquestionid" value="#rc.questions.id#">
<fieldset>
<cfloop query="rc.questions">
<cfset step ++ />
<cfset answer = "" />
<cfmodule template="../question/#rc.questions.template#/display.cfm" step="#step#" question="#rc.questions.question#" template1="#rc.questions.template#" fkquestionid="#rc.questions.id#" answer="#answer#" required="#rc.questions.required#" result="result#step#"/>
</cfloop>
<div class="form-actions">
<button type="submit" name="submit" class="btn btn-success">Submit answers</button>
</div>
</fieldset>
</form>
</cfoutput>
this is my display.cfm to view question and its questiontype like truefalse or yes or no.
<cfparam name="attributes.yesno" default="false">
<cfoutput>
<p>#attributes.step#) #attributes.question# <cfif attributes.required EQ 1><strong>* </strong></cfif></p>
<div class="answers">
<cfif attributes.yesno>
<input type="radio" name="answer" id="answer" value="yes"<cfif attributes.answer is "yes">Checked</cfif>><label for="truefalse">Yes</label><br>
<input type="radio" name="answer" id="answer" value="no"<cfif attributes.answer is "No">Checked</cfif>><label for="truefalse">No</label>
<cfelse>
<input type="radio" name="answer" id="answer" value="true"<cfif attributes.answer is "true">Checked</cfif>><label for="truefalse">True</label><br>
<input type="radio" name="answer" id="answer" value="False"<cfif attributes.answer is "False">Checked</cfif>><label for="truefalse">False</label>
</cfif>
</div>
</cfoutput>
here is the query to list question's records.
<cfquery name="list">
SELECT
questions.id,
questions.question,
questions.rank,
questions.required,
questiontypes.name as questiontype,
questiontypes.template as template,
surveys.name as surveysname,
surveys.thankyoumsg as thankyoumsg
FROM questions
INNER JOIN questiontypes ON questions.fkquestiontypeid = questiontypes.id
INNER JOIN surveys ON questions.fksurveyid = surveys.id
WHERE questions.fksurveyid = <cfqueryparam cfsqltype="cf_sql_bigint" value="#arguments.surveyid#">
</cfquery>
This is something that has bitten me a couple of times. I've always been pretty big on closing tags. But this is a situation where it will hurt. And be hard to debug if you don't understand the behavior of cfmodule. As the post above mine states, if you close the cfmodule tag, it will execute twice. This is because it's treated the same as a custom tag. There may be situations where you want to process part of the tag when it's first run and the rest after it's complete. You can access the ExecutionMode in the thisTag scope of the cfmodule page. With no closing tag, it's simply run in the thisTag.ExecutionMode = Start mode. If you close it, it runs the tag again in the End mode. If you aren't doing anything with the ExecutionMode inside the cfmodule's code, the whole thing will simply run again. This behavior is part of the reason that cfmodule can be so powerful.
When using the <cfmodule> tag you need to remember that ColdFusion will call that tag twice if you include an ending </cfmodule> tag OR if you close the opening tag like so <cfmodule ... />.
As stated on the cfmodule documentation page:
If you specify an end tag to cfmodule, ColdFusion calls your custom tag as if it had both a start and an end tag. For more information, see Handling end tags in the Developing ColdFusion Applications.
Handling end tags in the Developing ColdFusion Applications
In order to avoid this functionality do not close your <cfmodule> tag.
I got it, i must have not to close the cfmodule tag like <cfmodule />.

ColdFusion 9 ReReplace nth occurence of HTML tag

I have the following HTML stored in a variable in ColdFusion 9. I need to insert a new table row after the 4th </tr>. i.e. before the Submit button.
<form name="form1" id="form1" action="" method="post">
<table>
<tr style="visibility:hidden;display:none;"><td> <input type="hidden" id="ref1" name="ref1" value="1" > </td></tr>
<tr style="visibility:hidden;display:none;"><td> <input type="hidden" id="ref2" name="ref2" value="2" > </td></tr>
<tr>
<th style="text-align:left;">Name * </th>
<td><input type="text" name="foo" id="foo" size="30" maxlength="50" value=""></td>
</tr>
<tr>
<th title="Please enter plain text or HTML." style="cursor:help;text-align:left;">Comment * </th>
<td><textarea name="bar" id="bar" cols="40" rows="10" ></textarea></td>
</tr>
<tr>
<th colspan="1"></th>
<td>
<input style="width:80px" type="submit" value="Submit">
<input style="width:80px" type="button" value="Cancel">
</td>
</tr>
</table>
ReReplace seems like the way to go, but I'm having trouble getting the regexp right. Another option would be to split the string and rebuild it with my new HTML in the middle. Any suggestions would be appreciated.
Regex is the wrong tool for this - you want a HTML parser.
Here's how you can do it with JSoup:
<cfsavecontent variable="InputHtml">
[insert code from question]
</cfsavecontent>
<cfsavecontent variable="NewRow">
<tr><th>whatever</th><td>stuff</td></tr>
</cfsavecontent>
<!--- Read "Creating Objects From Jar Files" --->
<cfset jsoup = createObject('java','org.jsoup.Jsoup') />
<cfset HtmlDom = jsoup.parse(InputHtml) />
<cfset HtmlDom.select('tr:eq(4)').after( NewRow ) />
<cfoutput>
<pre>#XmlFormat(HtmlDom.body().html())#</pre>
</cfoutput>
You can see details of what selectors are supported in the JSoup Selector API
If you don't know/care how many lines are in the table, you can do...
HtmlDom.select('table>tbody').append( NewRow )
...to just add the new row at the end.
Creating Objects From Jar Files
The above code most likely wont work instantly if you copy and paste it, because your server doesn't know about JSoup - you need to download the Jar file and put it in a sensible location.
For CF9, you need to copy the jsoup-1.6.3.jar into your {coldfusion}/lib directory then restart the server.
For CF10, you can use this.JavaSettings in your Application.cfc (as described here) to place it in a different location.
For Railo and OpenBD, you can specify the location of the JAR file as a third argument, e.g:
<cfset jsoup = createObject('java','org.jsoup.Jsoup','lib/jsoup-1.6.3.jar') />
I recommend doing this with jQuery:
​$(document).ready(function(){
$($('form tr')[3]).after('<tr><td>row</tr></tr>');
});​
Much easier.