2 Submit buttons in 1 form - coldfusion

I have 2 submit buttons in my form.
<input type="submit" value="Save as Draft">
<input type="submit" value="Save">
Basically, what I want to do is when the user clicks on Save as Draft, it will proceed to bring all the form details to _update.cfm (without validating) and when the user clicks on Save, it will proceed to _validate.cfm and then to _update.cfm(validating and updating the database.)
HTML:
<cfset tx_name = "">
<cfif isDefined("form.tx_name")>
<cfset tx_name = form.tx_name>
</cfif>
<cfinclude template="_validate.cfm">
<cfif isDefined("form.tx_name")>
<cfinclude template="_update.cfm">
</cfif>
<form name="something">
<input type="text" name="tx_name" value="#tx_name#">
<input type="submit" value="Save as Draft">
<input type="submit" value="Save">
</form>
So basically what the above form does is that, by default, tx_name = " " and when user types something and submits, it will do all the validation in _validate.cfm and then proceed to _update.cfm to update it.
This is the intended way to work when the user clicks on Save button. However, for Save as Draft, I would like it to skip the _validate.cfm and straight bring all the form field data to _update.cfm.
The following is what I tried:
Attempt 1:
Instead of having <input type="submit" value="Save as Draft">, I used <input type="button" value="Save as Draft" onClick="location.href='_update.cfm';". And this didn't bring the form fields to _update.cfm and I figured out the reason, its because it is just redirecting to _update.cfm upon clicking the button.
So this made me think that I really need a submit button (to bring form data to the _update.cfm page).
But here is where I am lost as I have now 2 submit buttons. 1 of it is to work with _validate.cfm and the other to work without _validate.cfm.
So how do I go about to make Save as Draft not validate but update and Save to validate and update?

I would go down the road of both buttons having the same name, but a different value. I would also use button tags so that I could have better control over the display vs the value submitted. I would then not have to deal with if the display needs change, I would not have to change the processing. Last but not least I would wrap it so that it only operates in post
<cfscript>
if (cgi.request_method == "post") {
if (form.keyexists("tx_name") tx_name = form.tx_name;
if form.SaveMode == "Save") include "_validate.cfm";
if (form.keyexists("tx_name") include "_update.cfm";
}
</cfscript>
<form name="something" method="post">
<input type="text" name="tx_name" value="#tx_name#">
<button type="submit" name="SaveMode" value="Save as Draft">Save As Draft</button>
<button type="submit" name="SaveMode" value="Save">Save</button>
</form>

For that you have to add name for the two submit buttons. And using that name we can prevent the _validate.cfm inclusion, while submitting the form through clicking "Save as draft" button.
Also the form method should be POST, so that form scope will be available on action page, otherwise it'll available in URL scope.
<cfset tx_name = "">
<cfif isDefined("form.tx_name")>
<cfset tx_name = form.tx_name>
</cfif>
<cfif isdefined("form.Save")>
<cfinclude template="_validate.cfm">
</cfif>
<cfif isDefined("form.tx_name")>
<cfinclude template="_update.cfm">
</cfif>
<form name="something" method="post">
<input type="text" name="tx_name" value="#tx_name#">
<input type="submit" name="SaveAsDraft" value="Save as Draft">
<input type="submit" name="Save" value="Save">
</form>

I use a hidden form field called action. On the buttons I attach an onClick to change the value of action. On the form's action page I read that value and determine what to do. EX:
<input type="hidden" name="action" value="save" id="action">
<button type="submit" class="button button-basic-green" onclick="document.getElementById('action').value='save';"><span class="fa fa-save"></span> Save</button>
<button type="submit" class="button button-basic" onclick="document.getElementById('action').value='reload';"><span class="fa fa-repeat"></span> Save & Reload</button>
<button type="submit" class="button button-basic" onclick="document.location.href='./';return false;"><span class="fa fa-arrow-circle-o-left"></span> Cancel</button>

Related

Display data in HTML table or DataTable depending on radio button selection

I would like to give a user the option to display data in an HTML table or a DataTAble. I have a select dropdown that I am populating with a query output. After the user selects an option from the list they would select one of two radio buttons: (1) view HTML table, or (2) view DataTable. The user selects one of these radio buttons and then clicks on the submit button to display the results on a new page. The new page receives the form.value and inserts this into the query to produce the HTML table or DataTable.
I'm new to ColdFusion. It seems easier assign an action page to each radio button selection. I have made some attempt but nothing working yet. I'm guessing this may be a trivial task, but any help would be appreciated.
So on the form you would have your select dropdown and input
<select name="Species" class="dropdown">
<cfoutput query="species">
<option value="#species.Species#">#species.GenusSpecies#</option>
</cfoutput>
</select>
<input type="radio" name="Species" value="DataTable"> DataTable
<input type="radio" name="Species" value="HTML" checked="checked"> HTML Table
<input type="submit" value="Submit" class="buttons"></input>
How do I assign something to a radio button and then execute with submit? cfparam or cflocation??
Thanks.
in 1st cfm from your example you do
<body>
<select name="Species" class="dropdown">
<cfoutput query="species">
<option value="#species.Species#">#species.GenusSpecies#</option>
</cfoutput>
</select>
<form action="Species.cfm" name="mainform">
<input type="radio" name="Species" value="DataTable"/> DataTable
<input type="radio" name="Species" value="HTML" checked="checked"/> HTML Table
<input type="submit" value="Submit" class="buttons"/>
</form>
</body>
on a separate cfm. let's say species.cfm you'd do
<!---<cfdump var="#form#"> --->
<cfif form.species eq 'DataTable'>
display in datatables
<cfelse>
display in html
</cfif>

Variable is undefined when submitting form?

I have a form where I choose a date/year from a datepicker and depending
on what the user choose it bring up data from a table or a blank form.
I have two different submit buttons on the form depending on what is
chosen in the datepicker.
<cfset counter_2=0>
<form method="post" name="loantype" action="cse_execoffice_datepicker_test.cfm" onsubmit="return validateForm()">
....................code
<p><input type="submit" name="Submit" value="Submit" onclick(this.counter_2=1)></p>
<cfelse>
...more code
<p><input type="submit" name="Submit" value="Submit" onclick(this.counter_2=0)></p>
</form>
The problem im having is when I submit the form ONCLICK is not setting counter_2 to either '0 or 1'.
I want it to set it to 0 or 1 because depending on what is submitted.
<cfif FormSubmit eq "FormSubmitted">
<cfif counter_2 eq 0>
...code....
</cfif>
<ciif counter_2 eq 1>
...code..
</cfif>
</cfif>
The error I get is
Variable COUNTER_2 is undefined.
I have set the variable outside the form and even try it inside.
Do i have to set the counter_2 somewhere else?
You are mixing languages and incorrectly implementing them to boot. I think you are trying to do something like this so your form handler can see the counter_2 value?
Try this:
<form method="post" name="loantype" action="cse_execoffice_datepicker_test.cfm" onsubmit="return validateForm()">
<input type='hidden' name='counter_2' id='counter_2' value=''>
<cfif...>
<p><input type="submit" name="Submit" value="Submit" onclick="document.getElementById('counter_2').value=1"></p>
<cfelse>...
<p><input type="submit" name="Submit" value="Submit" onclick="document.getElementById('counter_2').value=0"></p>
</cfif>
</form>
This will allow a form field to be submitted with the value based on which element they clicked on.

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.

Accessing variables of a dynamic form

I am creating a form with cfloop and need to access each variable individually when submitting the form. I need to use the selected entries of the form in a loop that will add my selections to a database.
This is my form:
<form method="post">
<input type="hidden" name="isPost" value="1">
...
<cfoutput>
<cfloop query="client_admin_surveys">
<input type="text" size="35" name="surveyID" id="surveyID" value="#id#">
<input type="text" size="35" name="surveyName" id="surveyName" value="#name#">
<input type="checkbox" name="amplify" id="amplify">
<input type="checkbox" name="enchance" id="enchance">
<input type="checkbox" name="pacify" id="pacify">
<input type="checkbox" name="pacifyUrgent" id="pacifyUrgent">
</cfloop>
</cfoutput>
...
<input type="submit" name="submit" value="Submit">
</form>
After posting the form, the results group all of my selections because I have the same "name" for my form elements. I tried adding an i count next to each name to make it different but then I got a bit confused about how to process the fields.
You started down the correct path when you added the counter - go back and add that, something like:
<input type="checkbox" name="amplify#client_admin_surveys.currentRow#" id="amplify">
Would work.
I also sometimes like to add a form field for the 'counter' on the processing page
<input type="hidden" name="counter" value="#client_admin_surveys.recordCount#" />
Then on the processing page, you can loop over the counter and access the form fields using bracket notation
<cfloop from="1" to="#form.counter#" indexd="i">
<cfset thisAmplify = form["amplify" & i] />
<cfset thisEnhance = form["enhance" & i] />
<!---- more logic here --->
</cfloop>

Preserving input value of type="file" in ColdFusion on postback

I have a form in ColdFusion that initially has 5 input fields for file uploading. Should the user realize they have more than 5 files to upload in the process of attaching them, I would like the form to preserve the values when it submits itself for the change in # of fields.
Using the <cfform> tag with the preservedata="yes" attribute is supposed to accomplish this - but all I'm getting is a temp value stored in the input's value on resubmit that isn't displayed in the field nor works for a submission.
edit: Thanks for the great answers everyone, you all helped and were correct. I was able to implement Adam's suggested solution. Works great! Thanks!
function changeFieldCount() // javascript function for submit on input count change
{
var count = document.forms[0].numtotal.options[document.forms[0].numtotal.selectedIndex].value;
document.forms[0].action = "me.cfm?count=" + count;
document.forms[0].submit();
}
<cfparam name="url.count" default="5">
<cfform name="dispfiles" method="post" enctype="multipart/form-data" preservedata="yes">
<!--- looping for file input fields --->
<cfloop index="counter" from="1" to="#url.count#">
<cfinput type="file" name="file#counter#" size="50" maxlength="60"><br>
</cfloop>
<br>Number of Files to Attach:
<!--- looping for # of input selection--->
<cfselect name="numtotal">
<cfloop index="cnt" from="1" to="20" step="1">
<cfoutput>
<option value="#cnt#" <cfif #cnt# eq #url.count#>selected</cfif>>
#cnt#
</option>
</cfoutput>
</cfloop>
</cfselect>
<cfinput type="button" name="op-display" value="Display" onclick="changeFieldCount()">
<cfinput type="button" name="op-upload" value="Attach Files" onclick="submitfrm(this.form)">
<cfinput type="button" name="cancel" value=" Cancel " onclick="window.close()">
</cfform>
This is what I'm getting when I view source on the resulting submission:
<input name="file1" id="file1" type="file" value=".../cfusion.war/neotmp8858718543274653167.tmp" maxlength="60" size="50" /><br>
This is by design in all browsers for security reasons. There is no way you can insert the value for a file field.
To elaborate on #SpliFF's answer, what you need to do is dynamically create more file fields with JavaScript.
Here's an example that uses jQuery to make the JavaScript a little easier. I've also used a variable to track the number of file fields displayed so that they all have a unique number appended to their names, making it possible to loop over and uniquely identify them server-side.
<script type="text/javascript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/javascript">
//track the current number of file fields displayed
var numUploadFields = 5;
//attach an anonymous function to the button to add more fields
$(function(){
$("#add5").click(function(){
for (var i = 0; i < 5; i++){
numUploadFields += 1;
var newHTML = "<br/><input type='file' name='upload" +
numUploadFields + "' />";
$("#someSection").append(newHTML);
}
});
});
</script>
<form method="post" action="">
<div id="someSection">
<input type="file" name="upload1" /><br/>
<input type="file" name="upload2" /><br/>
<input type="file" name="upload3" /><br/>
<input type="file" name="upload4" /><br/>
<input type="file" name="upload5" />
</div>
<input type="button" id="add5" value="Add 5 more file fields" />
</form>
Build additional file inputs using JS DOM methods. Since you aren't leaving the page this is fast and nothing is lost.