ColdFusion form - display error details from database table - coldfusion

I have a database table with error id and error details for form validation errors.
In my ColdFusion form page, I have a list of error numbers 2,4,7 available. But I want to display errors like "Please enter name" etc.
I want to compare my list of errors with error id's in the database table and display the corresponding error in my form. Please let me know if there is any better way to do it. Thanks in advance!!
<form name = "empform" action="empform.cfm" method="post">
<cfoutput>
<table border="0">
<tr><td colspan="4" align="center" style="padding-bottom:20px;"><h2>Add Employee</h2></td></tr>
<cfif (structKeyExists(rc,"addemp"))>
<cfif rc.result.hasErrors()>
<tr>
<td colspan="4" style="border:2px solid red;">
Please review the following:
<ul>
<cfloop array="#rc.result.getFailureMessages()#" index="message">
<li>#message#</li>
</cfloop>
</ul>
</td>
</tr>
</cfif>
</cfif>
<cfset myArray = rc.result.getFailureMessages()>
<cfset myList = ArrayToList(myArray, ",")>
<cfquery name="qErrorMessages" datasource="#dsn#" >
Select * from ErrorMessages
</cfquery>
<tr>
<td><label><b>Emp Last Name</b></label></td>
<td><input name="lastname" type="text" value="" /></td>
<td><label><b>First Name</b></label></td>
<td><input name="FirstName" type="text" value="" /></td>
</tr>
<tr>
<td><label><b> Emp Birth Date</b></label></td>
<td><input name="birthdate" type="text" value="" /></td>
<td><label><b>Salary</b></label></td>
<td><input name="salary" type="text" value="" /></td>
</tr>
<tr><td style="padding-top:10px;">
<input type="submit" name = "addemp" value ="AddEmp /></td>
</tr>
</table>
</cfoutput>
</form>
I can display errors as shown above
Now I want to show actual messages. I am stuck up here.
My issue is not solved. I am able to loop through the table of errors only. Probably I need to loop through my list of error ids and then I need another loop to look up for the table errorId's to match then display the error.
I got it fixed with the below code.
<cfloop index="ind" list=#mylist#>
<cfquery datasource= "#dsn#" name="emperrors">
Select errorid,errmessage from errorcodes where errorid = #ind#
</cfquery>
#emperrors.errmessage#<br>
</cfloop>

Your question is short on details, but I'd probably query the table with the error messages, convert it to a struct, then drop that struct into a persistent scope that I could then reference later.
Something like:
<cfset errorStruct={}>
<cfloop query="qFormErrorMsgs">
<cfset errorStruct[error_id]=error_msg>
</cfloop>
<cfset application.errorStruct=errorStruct>
Then, when you want to display the error:
<p>Please fix the following error: #application.errorStruct[variables.error_id]#</p>
But that's just one way you might do it. Without more information in your question all you're going to get is guess (if you're lucky).

Alright, your answer detailing code should have been appended to your question via an edit, and still that's really not enough code. How are you determining your errors?
It sounds like your errors are something like this:
Please review the following:
2
3
6.
When what you want is error messages.
An easy way to update this is to load all your messages into an array where the index corresponds to the error codes.
<cfset ErrDetails=ArrayNew()>
<cfset ErrDetails[1]="You didn't enter your first name.">
<cfset ErrDetails[2]="You didn't enter your last name.">
<cfset ErrDetails[3]="You didn't enter a properly formatted birth date.">
<cfset ErrDetails[4]="It appears, from your birthdate, that your age is below 18">
And then, in your cfloop, you can
<cfloop array="#rc.result.getFailureMessages()#" index="message">
<li>#ErrDetails[message]#</li>
</cfloop>
Lastly it sounds like your errorcodes/messages are coming from a database. I'm not really sure that's necessary, but if you really want to keep it that way, that's fine. You can initialize this into the application scope so that you can call it later without rerunning the query, or just put it somewhere in flat text. However, if you want the application scope answer, here's a method.
<cflock scope="application" timeout="5">
<cfif not isDefined("application.ErrDetails")>
<cfquery name="getec">
select ErrID,ErrMessage from ErrorCodes
</cfquery>
<cfset Application.ErrDetails = []>
<cfloop query="getec">
<cfset Application.ErrDetails[ErrID]=ErrMessage>
</cfloop>
</cfif>
<cfset request.ErrDetails = Application.ErrDetails>
</cflock>
Once this is initiated, the cfloop displaying errors as I showed above can use #request.errDetails[message]#
If it's just running in one page, I wouldn't worry about creating an application variable. I'd just hardcode it in, or do a query there with a cfloop similar to above writing to a variables scope variable, not an application variable so the cflock isn't needed.
Unless you also have web based admin creating these rules, I'd probably ditch the table altogether and drop it directly into code, a cfinclude, a udf, or a custom tag.

Since the asker has updated their question with an answer.
Your answer needlessly repeats the query for each iteration.
Try something like this..
<cfquery datasource="#dsn#" name="GetECs">
select ErrorID,ErrMessage from ErrorCodes
where ErrorID in (<cfqueryparam cfsqltype="cf_sql_integer" list="yes" value="#mylist#">)
</cfquery>
<cfoutput query="GetECs">
#currentrow#. #ErrMessage#<br>
</cfoutput>
Notes:
One query is run.
For results, the where ErrorID in (<cfqueryparam cfsqltype="cf_sql_integer" list="yes" value="#mylist#">) is the same as saying where ErrorID in (#mylist#). However, the tag secures your queries against sql injection (the tactic of modifying variables to produce undesirable/malicious results in a query. Read up on cfqueryparam at http://help.adobe.com/livedocs/coldfusion/8/htmldocs/help.html?content=Tags_p-q_18.html

Related

Avoid duplicate with nested cfoutput and cfloop

I have made a dynamic form that combines a list of individuals. In this list, I have a field that contains the values of a dynamic list. My concern is that this field (#id_p#_state) is multiplied by the initial query and I want to avoid that. the result I have is for example if I have 10 results in the first query, each line of the second is x10
<cfinvoke component="cfc_query" method="methode_h" returnvariable="result">
<cfinvokeargument name="id_atser" value="#id#">
</cfinvoke>
<cfinvoke component="cfc_query" method="methode_state" returnvariable="result_state">
</cfinvoke>
<cfoutput query="result">
<tr>
<td>#lastname# #firstname# #id_personne#</td>
<cfloop from="1" to="#daysInMonth(createdate(datepart('yyyy',now()),form.date_periode,1))#" index="boucle">
<td><cfinput name="#id_personne#_date_presence" type="text" value="#dateformat(createdate(datepart('yyyy',now()),form.date_periode,boucle),'dd/mm/yyyy')#" size="7"></td>
<td>
<cfselect name="#id_p#_state" style="width: 32px;">
<cfloop query="result_state">
<cfoutput>
<option value="#id_state#">#description#</option>
</cfoutput>
</cfloop>
</cfselect>
</td>
</cfloop>
</tr>
</cfoutput>
You have a CFOUTPUT nested inside of a CFOUTPUT loop.
Get rid of the redundant CFOUTPUT around your option tag and this should clean up your output.

cfloop and dynamic variables from database

I have a small form that loops from 1 to 30 and assigns variables. After these variables are saved to the database, I am having some trouble figuring out how to set the value of the input as the value from the database. Here is a some of my code.
<cfloop index="i"
from="1"
to="30">
<select name="supply_#i#"
id="supply_#i#"
/>
<cfloop query="GetDescriptor">
<option value="#GetDescriptor.Code#">
#GetDescriptor.Descriptor#
</option>
</cfloop>
</select>
<input type="text"
name="quant_#i#"
id="quant_#i#"
/>
</cfloop>
Once complete, the user saves all 30 values to the database. When they attempt to view or edit the form, I need to show the previously selected value. I really don't know how to "nest" coldfusion variables together, or if it is even possible, but here is an example of the VIEW/EDIT .cfm that does not work, but shows you what I am trying to accomplish with the values.
<cfloop index="i"
from="1"
to="30">
<cfset "supply_#i#" = #QUERY.supply#i##>
<cfset "quant_#i#" = #QUERY.quant#i##>
<select name="supply_#i#"
id="supply_#i#"
/>
<cfloop query="GetDescriptor">
<option value="#GetDescriptor.Code#"
<cfif #VARIABLES.supply_#i## EQ '#GetDescriptor.Code#'>
SELECTED="SELECTED"
</cfif> >
#GetDescriptor.Descriptor#
</option>
</cfloop>
</select>
<input type="text"
name="quant_#i#"
id="quant_#i#"
value ="#VARIABLES.quant_#i##"
/>
</cfloop>
I think the easiest way to accomplish this is to use array notation. That is, use brackets instead of dots. Since all variables scopes are structs you can do this.
variables["foo"]
is equivalent to
variables.foo
So in your case, you probably want to reference
#VARIABLES["supply_#i#"]#
or, perhaps
#VARIABLES["supply_" & i]#
(Too long for comments)
What is the actual structure of the db table the values are inserted into? The variable names suggest you are using a denormalized db design. If so, consider normalizing the structure and storing the data in rows (SupplyCode, Quantity), rather than columns (Supply1,Qty1,Supply2,Qty2,....). The normalized structure is a lot easier to query, and supports as many or as few entries as needed.
Simply query the table and use a query loop to display the existing values. Use currentRow in place of the index variable i:
<cfquery name="existingEntries" ...>
SELECT SupplyCode, Quantity
FROM YourTable
ORDER BY .....
</cfquery>
<cfloop query="existingEntries">
<select name="SupplyCode_#currentRow#" id="SupplyCode_#currentRow#">
<cfloop query="GetDescriptor">
<option value="#GetDescriptor.Code#"
<cfif existingEntries.SupplyCode EQ GetDescriptor.Code>
SELECTED="SELECTED"
</cfif>>
#GetDescriptor.Descriptor#
</option>
</cfloop>
</select>
<input type="text" name="Quantity_#currentRow#" value ="#existingEntries.Quantity#" .... />
</cfloop>
NB: Typically you would store a FK ID from the GetDescriptor table, ie "SupplyID" rather than a string code or description, ie "SupplyCode"

ColdFusion not able to read option value of a cfselect

I'm a beginner with ColdFusion and I'm just trying out some basic functions.. I tried to loop over a simple query and put the values in a of a element. As value for the element I tried to set the id of each record of the query. After submiting I tried to read the selected value but I only get
You have chosen #getAll.id#
Here is my Code:
index.cfm
<cfquery datasource="testdb" name="getAll">
select *
from Personen
</cfquery>
<cfform action="chosen.cfm" method="post">
<cfselect name="listPersons">
<cfloop query="getAll">
<option value="#getAll.id#"><cfoutput>#getAll.id# #getAll.name# #getAll.vorname# #getAll.gebdate# <BR></cfoutput>
</cfloop>
</cfselect>
<cfinput type="Submit" name="Senden" value="Senden">
</cfform>
chosen.cfm
<cfoutput>You have chosen #listPersons#</cfoutput>
Can you tell me where I've made the mistake?
You didn't put your value attribute in a cfoutput tag, so it's being processed as #getAll.id# as the key in the struct instead of the value from the query. If you update your cfloop to be a cfoutput your issue will be fixed.
A couple pointers - You should scope the variable on chosen.cfm and you don't need to use cfform a regular form works just fine.
<cfquery datasource="testdb" name="getAll">
select *
from Personen
</cfquery>
<form action="chosen.cfm" method="post">
<select name="listPersons">
<cfoutput query="getAll">
<option value="#getAll.id#">#getAll.id# #getAll.name# #getAll.vorname# #getAll.gebdate#</option>
</cfoutput>
</select>
<input type="Submit" name="Senden" value="Senden">
</form>
chosen.cfm
<cfoutput>You have chosen #form.listPersons#</cfoutput>
Your code works for me with my test database but the value of listPersons on Chosen.cfm is not what I think you intended it to be. I would change the code to the following:
<cfquery datasource="testdb" name="getAll">
select *
from Personen
</cfquery>
<cfform action="chosen.cfm" method="post">
<cfselect name="listPersons">
<cfoutput query="getAll">
<option value="#getAll.id#">#getAll.id# #HTMLEditFormat(getAll.name)# #HTMLEditFormat(getAll.vorname)# #getAll.gebdate#
</cfoutput>
</cfselect>
<cfinput type="Submit" name="Senden" value="Senden">
</cfform>
What I did is I changed your CFLOOP to a CFOUTPUT then removed the CFOUTPUT you had. I also added the HTMLEditFormat functions just in case NAME or VORNAME contain some characters that will not play nice with the display. I assumed ID is numeric and GEBDATE is a date so figured no need on those. I also removed the BR element from your OPTION, not that I thought it was causing an issue but I could not see how that would effect the display either so seemed unneeded. I'd personally would close the OPTION but it is not needed to run. If you ultimate code is not running anything that CFFORM offers then I'd not use it and just use an HTML FORM.
Then on Chosen.cfm I would scope the output:
<cfoutput>#Form.listPersons#</cfoutput>
<cfoutput query="getAll">
#id# #name#
</cfoutput>
You don't need to repeat the query name inside of a cfoutput loop, if with cfoutput you specify the query you are looping over.

Next Page, for data editing

I did SEARCHing code, something like this.
--pageone.cfm--
<cfparam name="Form.studNo" default="" />
<form action="pagetwo.cfm" method="POST">
<label> Please insert ID:
<input name="studNo" value="<cfoutput>#Form.studNo#</cfoutput>" />
</label>
<input type="submit" value="Search" />
</form>
--pagetwo--
SELECT * FROM students
WHERE students_ID IN (#Form.studNo#)
On page two, I will display the details of student's info and user can edit a new information if the data is not right.
I'm thinking of, displaying data of one student per page and user can click Next for the next students (ID that has been inserted) on pageone.cfm
Can anyone help me with these?
#henry.
I did try something like this.
--example.cfm--
<CFPARAM NAME="StartRow" DEFAULT="1">
<CFPARAM NAME="DisplayRows" DEFAULT="1">
<CFQUERY NAME="getStudent" DATASOURCE="#dsn#"
CACHEDWITHIN="#CreateTimeSpan(0,0,15,0)#">
SELECT *
FROM students
</CFQUERY>
<CFSET ToRow = StartRow + (DisplayRows - 1)>
<CFIF ToRow GT getStudent.RecordCount>
<CFSET ToRow = getStudent.RecordCount>
</CFIF>
<HTML>
<HEAD>
<TITLE>Next/Previous Record Browsing</TITLE>
</HEAD>
<BODY>
<CFOUTPUT>
<H4>Displaying records #StartRow# - #ToRow# from the
#getStudent.RecordCount# data inserted.</H4>
</CFOUTPUT>
<!--- create the header for the table --->
<TABLE CELLPADDING="3" CELLSPACING="0">
<TR BGCOLOR="#888888">
<TH>Name</TH>
<TH>ID</TH>
<TH>Gender</TH>
<TH>E-mail</TH>
</TR>
<CFOUTPUT QUERY="getStudent" STARTROW="#StartRow#"
MAXROWS="#DisplayRows#">
<TR BGCOLOR="##C0C0C0">
<TD>#Name#</TD>
<TD>#ID#</TD>
<TD>#Gender#</TD>
<TD>#Email#</TD>
</TR>
</CFOUTPUT>
</TABLE>
<CFSET Next = StartRow + DisplayRows>
<CFSET Previous = StartRow - DisplayRows>
<!--- Create a previous records link if the records being displayed aren't the
first set --->
<CFOUTPUT>
<CFIF Previous GTE 1>
<A HREF="example.cfm?StartRow=#Previous#"><B>Previous #DisplayRows#
Records</B></A>
<CFELSE>
Previous Records
</CFIF>
<CFIF Next LTE getStudent.RecordCount>
<A HREF="example.cfm?StartRow=#Next#"><B>Next
<CFIF (getStudent.RecordCount - Next) LT DisplayRows>
#Evaluate((getStudent.RecordCount - Next)+1)#
<CFELSE>
#DisplayRows#
</CFIF> Records</B></A>
<CFELSE>
Next Records
</CFIF>
</CFOUTPUT>
</BODY>
</HTML>
You may use session to store the specified IDs in pageone.cfm, then go through the array of IDs and use array index as the current page number, and array length as the total page count.
However in this day and age, using JS to display a record at a time makes more sense.
Your approach is ok, but I'd recommend using existing libaries that do the trick of paginating and even constructing HTML for displaying page number buttons, next-previous links and what not.
Please revise http://paginationcfc.riaforge.org/ - a ColdFusion project that deals with pagination quite well and is very easy to implement, saving you tons of work. You could even set it do display one record per page, and the rest (next-previous buttons and maybe "page numbers") would be automagically done by the pagination component.
Ah, doing so (one big query and subsequent sub-queries) I strongly suggest caching.
HTH.

How to display each element in a ColdFusion query

I have written this piece of CF code to get and display the data from database. (Actually to populate text fields.) The problem: I am not getting values from the query, but I am correctly getting the number of records.
How am I supposed to access the values returned by the query via a cfloop? Below is my work.
<cfquery name="data_query" datasource="#dsn#">
SELECT
id,
name
FROM learning
</cfquery>
<cfloop query=data_query">
<li>
<div class="list_div clearfix">
<input type="text" value="#URLDecode(name)#">
</div>
</li>
</cfloop>
</cfquery>
You have two options:
Wrap the vars output line with <cfoutput /> tags:
<cfoutput>#id#: <input type="text" value="#name#"></cfoutput>
Use <cfoutput query="data_query"> loop instead of <cfloop ...>
For the sake of cleaner code I would prefer the second option so your code would be:
<cfquery name="data_query" datasource="#dsn#">
SELECT
id,
name
FROM learning
</cfquery>
<cfoutput query="data_query">
<li>
<div class="list_div clearfix">
#id#: <input type="text" value="#name#">
</div>
</li>
</cfoutput>
Also you should properly 'scope' your query columns when outputting. This will make your code easier to maintain in future, e.g. you'll always know that #data_query.name# belonged to the query and wasn't some string set by some other piece of code somewhere. And it'll speed up page performance - if you don't scope variables (this applies to all types of variables, not just queries), then CF will loop through the different scopes until it finds something with this value. So by scoping, you prevent CF having to loop.
<cfquery name="data_query" datasource="#variables.dsn#">
SELECT
id,
name
FROM learning
</cfquery>
<cfoutput query="data_query">
<li>
<div class="list_div clearfix">
#data_query.id#: <input type="text" value="#data_query.name#">
</div>
</li>
</cfoutput>
On the whole your logic was fine.. just a few typos and minor changes needed..
Give this a try.
<cfquery name="data_query" datasource="#dsn#">
SELECT
id,
name
FROM learning
</cfquery>
<cfloop query="data_query">
<li>
<div class="list_div clearfix">
#id#: <input type="text" value="#name#">
</div>
</li>
</cfloop>
And if you didn't know about it:
<cfdump var="#data_query#">
OR
<cfdump var="#data_query#" abort>
Will give you a beautiful display of came back from your query, or in any variable or structure.