Including or excluding range attribute in dynamically generate form field - coldfusion

I am using a query to dynamically create form fields, not all fields use the range attribute.
When using the cfif statement to include or exclude the range attribute I get an error:
See code below:
<cfoutput>
<input type="hidden" name="question_ids" id="question_ids" value="#valueList(rsQuestions.question_id)#">
</cfoutput>
<cfoutput query="rsQuestions" group="modid">
<table border="1" cellpadding="4" cellspacing="4" bgcolor="##0E777A" >
<tr>
<td colspan="2"><span class="style1">#rsQuestions.ModName#</span></td>
</tr>
<cfoutput>
<tr>
<td width="700" bgcolor="##FFFFFF">#rsQuestions.question#</td>
<td width="200" bgcolor="##FFFFFF">
<cfif rsQuestions.question_type_id eq 1>
<cfinput type="text" name="answer_#rsQuestions.question_id#"
message="#rsQuestions.Message#"
tooltip="#rsQuestions.Tooltip#"
validate="#rsQuestions.Validate#"
<cfif #rsQuestions.Range# neq "">
range = "#rsQuestions.Range#"
</cfif>
required="#rsQuestions.mandatory#"
size="#rsQuestions.Size#">
<cfelseif rsQuestions.question_type_id eq 2>
<cfquery name="rsOptions" datasource="dsTest">
SELECT option_id, [option], question_id
FROM questionnaire_question_options
WHERE (question_id = #rsQuestions.question_id#)
</cfquery>
<cfselect enabled="yes"
name="answer_#rsQuestions.question_id#"
multiple="no"
query="rsOptions"
value="option"
display="option">
</cfselect>
</cfif>
</td>
</tr>
</cfoutput>
</table>
</cfoutput>
How can I structure the above statement to include or exclude the 'range' attribute?

As user8675309 (Jenny?) mentioned, you cannot nest <cfif> tags inside another CF tag. So you need to separate those statements out. Here is one way you could do that:
....
<cfif rsQuestions.question_type_id eq 1>
<cfif rsQuestions.Range neq "">
<cfinput type="text" name="answer_#rsQuestions.question_id#"
message="#rsQuestions.Message#"
tooltip="#rsQuestions.Tooltip#"
validate="#rsQuestions.Validate#"
range="#rsQuestions.Range#"
required="#rsQuestions.mandatory#"
size="#rsQuestions.Size#">
<cfelse>
<cfinput type="text" name="answer_#rsQuestions.question_id#"
message="#rsQuestions.Message#"
tooltip="#rsQuestions.Tooltip#"
validate="#rsQuestions.Validate#"
required="#rsQuestions.mandatory#"
size="#rsQuestions.Size#">
</cfif>
<cfelseif rsQuestions.question_type_id eq 2>
....

As mentioned, you can't nest a cfif (or any CF tag) inside another CF tag.
One thing you can do if you really need dynamic attributes is to use the "attributeCollection" attribute.
(ColdFusion 8 or higher.)
Something like:
<cfset inputAttr=structNew()>
<cfset inputAttr.type="text">
<cfset inputAttr.name="answer_#rsQuestions.question_id#">
<cfset inputAttr.message="#rsQuestions.Message#">
<cfset inputAttr.tooltip="#rsQuestions.Tooltip#">
<cfset inputAttr.validate="#rsQuestions.Validate#">
<cfif rsQuestions.Range neq "">
<cfset inputAttr.range = "#rsQuestions.Range#">
</cfif>
<cfset inputAttr.required="#rsQuestions.mandatory#">
<cfset inputAttr.size="#rsQuestions.Size#">
<cfinput attributecollection="#inputAttr#">

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 to insert a pagebreak in cfdocument after every 4 records

I have the following cfdocument code:
<cfdocument format="pdf" orientation = "landscape" bookmark="Yes" marginleft=".25" marginright=".25" marginTop = ".75" marginbottom=".75" scale="90" localUrl="yes">
<cfoutput>
<cfdocumentsection name="Summary Page" marginleft=".25" marginright=".25" marginTop = "1.65" marginbottom="1" >
<cfdocumentitem type="header">
<center>
<table width="1000" height="200" cellpadding="3" cellspacing="0">
<tr><td>Header Page</td></tr>
</table>
</center>
</cfdocumentitem>
<cfloop query="first_query">
<cfquery name="getDetails" dbtype="query">
select * from first_query
where type= <cfqueryparam cfsqltype="cf_sql_varchar" value="#Type#">
</cfquery>
<cfsavecontent variable="trhead">
<tr class="bigbluecolor" style="text-align:center;">
<td width="6%">Term</td<
</tr>
</cfsavecontent>
#trhead#
<cfloop query="getDetails">
<tr align="center">
<td width="6%">#Listfirst(TermYears,'.')# Years</td>
</tr>
<cfif getDetails.recordcount GT 6 AND getDetails.currentRow EQ 6>
<cfdocumentitem type="pagebreak"/>
#trhead#
</cfif>
</cfloop>
</table>
</td></tr></table>
</cfloop>
</cfoutput>
</cfdocumentsection>
</cfdocument>
However, it does not do the page break. It shows empty pages at the top and then it starts breaking anywhere it wants. I want my inner loop to break after 4 records and the <TH> header to repeat itself again on the start of the second page.
The trhead variable contains the code which I have wrapped with the savecontent to show it.
Can anyone explain what I am missing?
The unpredictability of the page breaks is because of this:
<cfif getDetails.recordcount GT 6 AND getDetails.currentRow EQ 6>
If getDetails has less than 6 records, that condition will never return true. Plus, if you have 12 or more records, it won't return true. I suggest this approach. First, add this to first_query:
order by type
Then build your content like this:
<cfsavecontent variable="trhead">
<tr class="bigbluecolor" style="text-align:center;">
<td width="6%">Term</td>
</tr>
</cfsavecontent>
<cfoutput query="first_query">
other content goes here
<cfif currentRow mod 6 is 0>
<cfdocumentitem type="pagebreak"/>
#trhead#
</cfif>
</cfoutput>

Invalid tag nesting configuration in ColdFusion 10?

How do I get around this ColdFusion error?
I'm following this ColdFusion tutorial. When I tried to implement the code in ColdFusion 10 I got the following error:
Invalid tag nesting configuration. A query driven queryloop tag is
nested inside a queryloop tag that also has a query attribute. This is
not allowed. Nesting these tags implies that you want to use grouped
processing. However, only the top-level tag can specify the query that
drives the processing.
The error occurred in line 76
74 : </cfloop>
75 : </tr>
76 : <cfoutput query="data" startRow="2">
77 : <tr>
78 : <cfloop index="c" list="#colList
Here is the code:
<cfset showForm = true>
<cfif structKeyExists(form, "xlsfile") and len(form.xlsfile)>
<!--- Destination outside of web root --->
<cfset dest = getTempDirectory()>
<cffile action="upload" destination="#dest#" filefield="xlsfile" result="upload" nameconflict="makeunique">
<cfif upload.fileWasSaved>
<cfset theFile = upload.serverDirectory & "/" & upload.serverFile>
<cfif isSpreadsheetFile(theFile)>
<cfspreadsheet action="read" src="#theFile#" query="data" headerrow="1">
<cffile action="delete" file="#theFile#">
<cfset showForm = false>
<cfelse>
<cfset errors = "The file was not an Excel file.">
<cffile action="delete" file="#theFile#">
</cfif>
<cfelse>
<cfset errors = "The file was not properly uploaded.">
</cfif>
</cfif>
<cfif showForm>
<cfif structKeyExists(variables, "errors")>
<cfoutput>
<p>
<b>Error: #variables.errors#</b>
</p>
</cfoutput>
</cfif>
<form action="test.cfm" enctype="multipart/form-data" method="post">
<input type="file" name="xlsfile" required>
<input type="submit" value="Upload XLS File">
</form>
<cfelse>
<style>
.ssTable {
width: 100%;
border-style:solid;
border-width:thin;
}
.ssHeader { background-color: #ffff00; }
.ssTable td, .ssTable th {
padding: 10px;
border-style:solid;
border-width:thin;
}
</style>
<p>
Here is the data in your Excel sheet (assuming first row as headers):
</p>
<cfset metadata = getMetadata(data)>
<cfset colList = "">
<cfloop index="col" array="#metadata#">
<cfset colList = listAppend(colList, col.name)>
</cfloop>
<cfif data.recordCount is 1>
<p>
This spreadsheet appeared to have no data.
</p>
<cfelse>
<table class="ssTable">
<tr class="ssHeader">
<cfloop index="c" list="#colList#">
<cfoutput><th>#c#</th></cfoutput>
</cfloop>
</tr>
<cfoutput query="data" startRow="2">
<tr>
<cfloop index="c" list="#colList#">
<td>#data[c][currentRow]#</td>
</cfloop>
</tr>
</cfoutput>
</table>
</cfif>
</cfif>
Try this:
<cfoutput>
<cfloop query="data" startRow="2">
<tr>
<cfloop index="c" list="#colList#">
<td>#data[c][currentRow]#</td>
</cfloop>
</tr>
</cfloop>
</cfoutput>

Delete items unchecked from a form using ColdFusion

When a user deselects an item (by unchecking the checkbox) from the form, I want the corresponding data to be deleted from the database.
Here is what my form looks like:
Category
Item 80 626
1.Item # 1 (87) chk chk
2.Item # 2 (59) chk chk
So basically, the list looks like this:
DB_list = (80|87, 626|87, 80|59, 626|59)
Now if a user deselects one of these items 80|87, I want it to be deleted from the database like so:
DELETE FROM TBL
WHERE Item = 87
AND Category = 80
So on form submit, the list becomes
New_List = (626|87, 80|59, 626|59)
How do we delete 80|87?
This is one way to do it:
<cfoutput>
<cfset DB_list = "80|87,626|87,80|59,626|59" />
<cfset New_List = DB_list />
<cfset myitems="80,626">
<cfset mycategories = "87,59"/>
<cfif structKeyExists(form,"fieldnames")>
<!-- on submit -->
<cfif structKeyExists(form,"listitem")>
<cfset New_List = form.listitem>
</cfif>
<br />RESULT:<br />
DB_list:#DB_list#<br />
New_List:#New_List# <br /><br />
<cfloop from="1" to="#ListLen(DB_list)#" index="ix">
<cfset listitem = ListGetAt(DB_list,ix)>
<cfif ListFindNoCase(New_List,listitem) eq 0>
<!-- hence: split in javascript -->
<cfset listitemarray=ListToArray(listitem,"|")/>
<cfset itemid=listitemarray[1] />
<cfset categoryid=listitemarray[2] />
<cfquery>
DELETE FROM TBL
WHERE Item = <cfqueryparam cfsqltype="CF_SQL_INTEGER" value="#itemid#">
AND Category = <cfqueryparam cfsqltype="CF_SQL_INTEGER" value="#categoryid#">
</cfquery>
</cfif>
</cfloop>
</cfif>
<form name="tstForm" id="tstForm" method="post" action="">
<table>
<tr>
<td> </td>
<cfloop from="1" to="#ListLen(mycategories)#" index="lstindex1">
<td>Category #ListGetAt(mycategories,lstindex1)#</td>
</cfloop>
</tr>
<cfloop from="1" to="#ListLen(myitems)#" index="lstindex2">
<tr>
<cfset itemid=#ListGetAt(myitems,lstindex2)# />
<td>item #itemid#</td>
<cfloop from="1" to="#ListLen(mycategories)#" index="lstindex3">
<cfset catid=#ListGetAt(mycategories,lstindex3)# />
<td>
<input type="checkbox" id="listitem_#itemid#_#catid#" name="listitem" value="#itemid#|#catid#" <cfif ListFindNoCase(New_List,"#itemid#|#catid#",",") gt 0>checked</cfif>/>
</td>
</cfloop>
</tr>
</cfloop>
</table>
<button type="submit">Submit</button>
</form>
</cfoutput>
Run this code here
My approach would be to have a hidden field in the form that has all the available values for the checkboxes. Then when the form is submitted, compare what's in the hidden form field with what's in the checkbox field. Whatever the hidden field has that the check box field does not can be deleted.
Without the use of JavaScript, Dan Bracuk's solution would work the best for your stated requirements. However, another simpler approach to this problem is to just delete all previous choices then re-insert whatever items are still checked. Then there is no need to compare old and new values to determine what has changed.
How about
DELETE
FROM tbl
WHERE NOT CONVERT(varchar(20), Item) + '|' + CONVERT(varchar(20), Category)
IN <cfqueryparam cfsqltype="CF_SQL_varchar" value="#form.new_list#" list="yes">
My approach using sql server is to delete all the list items from the db, and then add only the ones that have been submitted by the form. All delete and add queries should be put into a single transaction, so if anything fails you can make o rollback.

Issues with coldfusion query function call inside a query loop

I have a query loop and inside that loop, I make a cfc function call to return a second query. It's doing weird things with the display:
In the example below, instead of making a function call to obtain the second query, I create a simple loop. This displays fine. View the actual page here
<cfoutput>
<cfif qCal.recordcount>
<a class="control" onClick="return hs.getExpander(this).printHtml()" href="##">Print</a>
</cfif>
<table width="100%" cellspacing="0" cellpadding="4">
<cfloop query="qCal">
<tr>
<td align="middle" valign="top" style="width:150px;">
<a title="View full-sized image" onclick="return hs.expand(this)" href="/images/classes/#qCal.image#" class="highslide"><img src="/images/classes/#qCal.thumb#" class="resize2"></a></td>
<td>
<table cellspacing="0" cellpadding="3">
<tr>
<td colspan="2" class="textNormal"><h2>#qCal.title#</h2></td>
</tr>
<tr>
<td class="textNormal"><strong>Date:</strong></td>
<td class="textNormal"><strong>Time:</strong></td>
</tr>
<cfloop from="1" to="5" index="i"> <!--- basic loop --->
<tr>
<td>#i#</td>
<td></td>
</tr>
</cfloop>
</table>
</td>
</tr>
</cfloop>
</table>
</cfoutput>
But, as soon as I make a function call to obtain a secondary query, inexplicable things happen with the display. View the actual page here (which renders half-cooked html code).
<cfoutput>
<cfif qCal.recordcount>
<a class="control" onClick="return hs.getExpander(this).printHtml()" href="##">Print</a>
</cfif>
<table width="100%" cellspacing="0" cellpadding="4">
<cfloop query="qCal">
<cfsilent>
<cfset qCalItems = o_system.getCalendarItems(
start=dateformat(vStartDate,"yyyy-mm-yy"),
end=dateformat(vEndDate,"yyyy-mm-yy"),
classID=qCal.classID,
forQuarterlyCalendar=true,
order_by="i.startDate")>
</cfsilent>
<tr>
<td align="middle" valign="top" style="width:150px;">
<a title="View full-sized image" onclick="return hs.expand(this)" href="/images/classes/#qCal.image#" class="highslide"><img src="/images/classes/#qCal.thumb#" class="resize2"></a></td>
<td>
<table cellspacing="0" cellpadding="3">
<tr>
<td colspan="2" class="textNormal"><h2>#qCal.title#</h2></td>
</tr>
<tr>
<td class="textNormal"><strong>Date:</strong></td>
<td class="textNormal"><strong>Time:</strong></td>
</tr>
<cfloop query="qCalItems">
<tr bgcolor="#iif(qCalItems.CurrentRow MOD(2) eq 1,de('ffffff'),de('EFEFEF'))#">
<td>#DayOfWeekAsString(dayofweek(qCalItems.startDate))# #dateformat(qCalItems.startDate,"dd mmm yyyy")#</td>
<td>#qCalItems.startTime#-#qCalItems.endTime#</td>
</tr>
</cfloop>
</table>
</td>
</tr>
</cfloop>
</table>
</cfoutput>
UPDATE - CFC CODE ADDED
NOTE: Function returns either a struct or a query depending on the argument "forQuarterlyCalendar". It definitely returns a query object in this case. I have dumped the query out and confirm that it is a valid query object.
<cffunction name="getCalendarItems" access="remote" returntype="any" output="false" returnformat="json">
<cfargument name="classID" type="any" required="false" default="">
<cfargument name="forSelect" type="boolean" required="false" default="false">
<cfargument name="forQuarterlyCalendar" type="boolean" required="false" default="false">
<cfargument name="start" type="any" required="false" default="">
<cfargument name="end" type="any" required="false" default="">
<cfargument name="order_by" type="any" required="false" default="c.title">
<cfargument name="sort_direction" type="any" required="false" default="asc">
<cfargument name="json" type="boolean" required="false" default="true">
<cfargument name="must_have_store_item" type="boolean" required="false" default="true">
<cfset var qClass = 0>
<cfset var realStart = "">
<cfset var realEnd = "">
<cfset var results = []>
<cfset var vUrl = "">
<cfset var vId = "">
<cfset var vTitle = "">
<cfset var vStart = "">
<cfif len(trim(arguments.start))>
<cfset realStart = EpochTimeToLocalDate(arguments.start)>
</cfif>
<cfif len(trim(arguments.end))>
<cfset realEnd = EpochTimeToLocalDate(arguments.end)>
</cfif>
<cfquery name="qClass" datasource="#application.datasource#">
select <cfif arguments.forSelect>
c.title, i.calendarItemID as id, convert(varchar, i.startDate, 103)+' '+i.startTime+'-'+i.endTime as text
<cfelseif arguments.forQuarterlyCalendar>
c.description, i.calendarItemID as id, i.startDate, i.startTime, i.endTime
<cfelse>
i.calendarItemID, i.startDate, i.startTime, i.endTime
,c.classID, c.title, c.description, c.price, c.places, c.exclusive, c.discounted, c.url
,s.storeItemID
</cfif>
from calendarItem i
<cfif arguments.must_have_store_item>
join storeItem s on s.entityID = i.calendarItemID and s.storeItemTypeID = 3
</cfif>
join class c on c.classID = i.classID and c.active=1
where i.active=1
<cfif isnumeric(arguments.classID)>
and i.classID = <cfqueryparam value="#arguments.classID#" cfsqltype="cf_sql_integer">
</cfif>
<cfif len(trim(arguments.start))>
<cfif arguments.forQuarterlyCalendar>
and i.startDate >= <cfqueryparam value="#arguments.start#" cfsqltype="cf_sql_date">
<cfelse>
and i.startDate >= <cfqueryparam value="#dateformat(realStart,'yyyy-mm-dd')#" cfsqltype="cf_sql_date">
</cfif>
</cfif>
order by #arguments.order_by# #arguments.sort_direction#
</cfquery>
<cfif qClass.recordcount>
<cfif not arguments.forSelect and not arguments.forQuarterlyCalendar>
<cfloop query="qClass">
<cfset vUrl = qClass["url"]>
<cfset vId = qClass["storeItemID"]>
<cfset vTitle = qClass["title"]>
<cfset vStart = GetEpochTimeFromLocal(qClass.startDate)>
<cfif not len(trim(url)) or len(trim(url)) is 0>
<cfset vUrl = "#application.webroot#/class_detail.cfm?id=#vId#">
</cfif>
<cfset s = structnew()>
<cfset s["id"] = vId>
<cfset s["url"] = vUrl>
<cfset s["title"] = vTitle>
<cfset s["start"] = vStart>
<cfset arrayappend(results, s)>
</cfloop>
<cfelse>
<cfset results = qClass>
</cfif>
</cfif>
<cfif arguments.json>
<cfcontent type="application/json">
</cfif>
<cfreturn results>
</cffunction>
You need to var scope 's':
<cfset s = structnew()>