cfoutput grouped query - seeing the result - coldfusion

I'd like to have a look at the query that would be inside this:
<cfoutput query="myQuery" group="ID">
<cfdump var="#theResultingRows#" />
</cfoutput>
Is there a way of getting the internal query results other than running a QoQ with matching id?

Yes, you can use nested cfoutput tags as described in the documentation. You can also use a loop and array notation to save typing.
<cfoutput query="x" group="id">
id is #id#<hr>
<cfoutput>
<cfloop list="#x.columnlist#" index="field">
#field# is #x[field][currentrow]#
</cfloop>
<br>
</cfoutput>
</cfoutput>

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.

How do I show multiple tabs using the "read" function for CFSPREADSHEET?

I would like to show multiple tabs, i.e. multiple sheets, from an xls file in the browser using Coldfusion. I have the logic pretty worked out, but I'm not sure if there is a way to do it. My logic would be as follows:
<cfspreadsheet
action="read"
format="html"
src="test.xls"
name="Spreadsheet"
<cfloop index="i" from="1" to="5"> <!--- or however many tabs there are --->
sheet="#i#"
</cfloop>
>
<table>
<cfoutput>
#Spreadsheet#
</cfoutput>
</table>
Now I know this code doesn't work, so I was looking for a similar solution. Thank you all in advance.
Try putting cfloop around cfspreadsheet
<cfloop from="1" to="5" index="i">
<cfspreadsheet
action="read"
format="html"
src="test.xlsx"
sheet="#i#"
name="spreadsheet">
<cfdump var="#spreadsheet#"><br>
</cfloop>

ColdFusion form - display error details from database table

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

ColdFusion cfoutput & excluding items

<cfif dir.name IS NOT "Thumbs.db">
This code excludes Thumbs.db from being called in the cfoutput query, but what if I want another file excluded? Not sure how to exclude more than one item though.
Right now have
<cfset counter = 1 />
<cfoutput query="dir1">
<cfif !listfindNoCase( 'Thumbs.db,2. Electric Accounts Tracking Report.xls,1. Electric Accounts Performance Analytics.xls', dir1.name) >
<a href="/091_AU20100226/020_Cost_Analyses/010_Electric/Flatten_Files/#dir1.name#" target="_blank">
#dir1.name#</a><br />
<cfset counter++ /> </cfif> </cfoutput>
You can use listFind() or listFindNoCase().
<cfif !listfindNoCase( 'Thumbs.db,otherFile.txt', dir.name) >
...do stuff...
</cfif>

Nesting queries in CF

I'm using this code to display a list of platforms. If a platformID was specified upon entering the page, I would like to create a list of genres underneath the specified platform.
browse.cfm was accessed via a link that specified a platformID of 1
browse.cfm will list all available platforms
browse.cfm will now list all available genres under platformID of 1.
<ul>
<li>Browse</li>
<cfoutput query="qGetPlatforms">
<li>
#qGetPlatforms.pName#
<cfif URL.platformID EQ qGetPlatforms.platformID>
<ul>
<cfoutput query="qGetGenres">
<li>#qGetGenres.gName#</li>
</cfoutput>
</ul>
</cfif>
</li>
</cfoutput>
</ul>
By using this approach, however, I'm getting an invalid nesting configuration. How do I fix this? Or is there another approach to achieve the same idea?
Thanks
MY queries:
<!---Get platforms--->
<cffunction
name="fGetPlatforms"
access="public"
returntype="query"
output="false"
hint="I get all the platforms">
<!---Local var--->
<cfset qGetPlatforms = "">
<!---Database query--->
<cfquery name="qGetPlatforms" datasource="#REQUEST.datasource#">
SELECT
platforms.platformID,
platforms.platformName AS pName
FROM
platforms
</cfquery>
<cfreturn qGetPlatforms>
</cffunction>
<!---Get genres--->
<cffunction
name="fGetGenres"
access="public"
returntype="query"
output="false"
hint="I get all the genres">
<!---Local var--->
<cfset qGetGenres = "">
<!---Database query--->
<cfquery name="qGetGenres" datasource="#REQUEST.datasource#">
SELECT
genres.genreID,
genres.genreName AS gName
FROM
genres
</cfquery>
<cfreturn qGetGenres>
</cffunction>
You can use <cfloop query="qGetGenres"></cfloop>, they can be nested.
IMO, using cfoutput for looping over the queries is old style and should be avoided. Use cfoutput for output, cfloop for looping and you'll have more readable code.
more food for thought is to use an inner join between the two tables, combine and retrieve everything in one query and then use cfoutput's group attribute to display the results:
<cfset URL.platformID = int(val(URL.platformID))>
<cfquery name="getPlatformsAndGenres" datasource="#REQUEST.datasource#">
SELECT
p.platformID AS platformID
,p.platformName AS pName
,g.genreID AS genreID
,g.genreName AS gName
FROM
platforms p
INNER JOIN genres g
ON p.platformID = g.platformID
WHERE
p.platformID = <cfqueryparam cfsqltype="cf_sql_integer" value="#URL.platformID#">
ORDER BY
pName
,genreName
</cfquery>
Once you have everything in one query, you can use <cfoutput query="getPlatformsAndGenres" group="pName">
to lessen your code:
<ul>
<li>Browse</li>
<cfoutput query="getPlatformsAndGenres" group="pName">
<li>
#pName#
<ul>
<cfoutput>
<li>#gName#</li>
</cfoutput>
</ul>
</cfif>
</li>
</cfoutput>
</ul>