Delete items unchecked from a form using ColdFusion - 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.

Related

Mura Display Form Data in a Page

I have some custom html code where i need to get the name and image an caption from the form i created in the mura backend, how can i do this, i searched everywhere in the google groups but nothing related found, i just need a start what to do and how to find the saved data and for cfoutput i think i need to do iterations
<cfset it = $.getBean('content').loadBy(title='myform')>
<cfdump var="#it#">
<cfif it.hasNext()>
<ul>
<cfloop condition="it.hasNext()">
<cfset item = it.next()>
<li>
#esapiEncode('html', item.get('name'))#
</li>
</cfloop>
</ul>
i need to get the form and display the data in ul > li format as above but it is gives me error on hasnext() is not defined, which somewhat does make sense, but i am not sure what i am missing here
OK. I can confirm that this works, using MURA CMS 7.1 & form builder.
ContentID:
The important part is to reference the form by its 'ContentID', which you can find in the 'Form Builder -> Form -> Advanced' section.
Variable References:
Also you will need to change the references to 'formContentId' & 'wddxImageFieldName', respectively.
Set-up:
To test this, just place it into your repective Themes template, and make sure that you have made at least one form submission
Based on Steve Withington's code, at:
https://gist.githubusercontent.com/stevewithington/5963610/raw/4d8bca4675500075b0a5831db52ccc9b8bf0bf57/mura-form-results.cfm
<cfscript>
rsData = QueryNew('');
dcm = $.getBean('dataCollectionManager');
formContentId = '856499BD-01E2-48C9-CD1A0430D859E81B';
wddxImageFieldName = 'AVATAR_ATTACHMENT';
</cfscript>
<cfif !Len($.event('responseid'))>
<!--- All Form Submission Results --->
<cfscript>
formBean = $.getBean('content').loadBy(contentID=formContentId);
if ( !formBean.getIsNew() ) {
currentFieldList = dcm.getCurrentFieldList(formBean.getContentID());
data = {
sortby = 'entered'
,sortdirection = 'desc'
,keywords = ''
,siteid = $.event('siteid')
,contentid = formBean.getContentID()
};
rsData = dcm.getData(data);
}
</cfscript>
<cfif !rsData.recordcount>
<h3>Sorry, either the form does not exist, or no records have been submitted yet.</h3>
<cfelse>
<table cellspacing="5" cellpadding="5" border="1">
<!--- FieldNames --->
<thead>
<tr>
<th> </th>
<th>Date/Time Entered</th>
<cfloop list="#currentFieldList#" index="fieldName">
<th>#esapiEncode('html', fieldName)#</th>
</cfloop>
</tr>
</thead>
<!--- Actual Output --->
<tbody>
<cfloop query="rsData">
<tr>
<!--- Edit --->
<td>
Edit
</td>
<!--- The Date/Time Stamp --->
<td>
#entered#
</td>
<!--- The Data --->
<!--- Forms are stored as WDDX files ... so we need to unpack them --->
<cfwddx action="wddx2cfml" input="#data#" output="record" />
<cfloop list="#currentFieldList#" index="fieldName">
<td>
<cfif StructKeyExists(record, fieldName)>
#record[fieldName]#
<cfif CompareNoCase(fieldName,wddxImageFieldName) EQ 0>
<img src="#$.getURLForImage(record[fieldName])#">
</cfif>
<cfelse>
</cfif>
</td>
</cfloop>
</tr>
</cfloop>
</tbody>
</table>
</cfif>
</cfif>

looping over a list with multiple and selected the selected ones

I'm working on code where I am getting two lists. I'm trying to use those lists to pre-select items in select box having the "multiple" attribute. However, I am unable to maintain the selections.
Code:
<select name="sbbox" id="sbbox" class="can" multiple>
<cfloop list="#lstFinds#" index="k" delimiters=",">
<option value="#k#" <cfif #listfindnocase(k,getproducts.ptype)#>selected</cfif>>#k#</option>
</cfloop>
</select>
Sample values:
lstFinds = abc,xyz
getproducts.ptype also contains values like abc,xyz
I want to keep both selected, if both values exists for the user. If one exists, keep one selected. If none are selected, keep none.
I also tried using listContains, but it did not work.
Transferred from pastebin linkL
The ptype values are coming as comma separated in the database ie "abc,wed,mon,def". Whatever those values are, I need to match and selected the ones which have the same value in the listFind. I hope I made it clearer.
<cfset lstFinds = 'abc,xyz,def,www,kkr,mon,tue,wed'>
<cfquery name="getproducts" datasource="cdfg">
select ptype
from
mytable
where
ID = <cfqueryparam cfsqltype="cf_sql_integer" value="#id#">
</cfquery>
<select name="sbbox" id="sbbox" class="can" multiple>
<cfloop list="#lstFinds#" index="k" delimiters=",">
<option value="#k#" <cfif #listfindnocase(k,getproducts.ptype)#>selected</cfif>>#k#</option>
</cfloop>
</select>
There are three things wrong with this:
<cfloop list="#lstFinds#" index="k" delimiters=",">
<option value="#k#" <cfif #listfindnocase(k,getproducts.ptype)#>selected</cfif>>#k#</option>
</cfloop>
First, as others have mentioned, in the listfindnocase function, the list comes first.
Next, the reason you are not getting the desired results after sorting out the first problem, is that getproducts.ptype is not a list. It is the value from the first row of the query. To get all the values in a list, use the valuelist() function.
Finally, the correct syntax for having an option selected is selected="selected". So the code block above should be this:
<cfloop list="#lstFinds#" index="k" delimiters=",">
<option value="#k#"
<cfif listfindnocase(ValueList(getproducts.ptype), k)>
selected="selected"
</cfif>>#k#
</option>
</cfloop>
Ok, the asker provided the following code via a Pastebin
<cfset lstFinds = 'abc,xyz,def,www,kkr,mon,tue,wed'>
<cfquery name="getproducts" datasource="cdfg">
select ptype
from
mytable
where
ID = <cfqueryparam cfsqltype="cf_sql_integer" value="#id#">
</cfquery>
these are coming from database column ptype of a table as: abc,wed,mon,def
<select name="sbbox" id="sbbox" class="can" multiple>
<cfloop list="#lstFinds#" index="k" delimiters=",">
<option value="#k#" <cfif #listfindnocase(k,getproducts.ptype)#>selected</cfif>>#k#</option>
</cfloop>
</select>
I ran the following code as at cflive.net
<cfset lstFinds = 'abc,xyz,def,www,kkr,mon,tue,wed'>
<cfset getProducts = {pType = "abc,wed,mon,def"}>
<cfoutput><select name="sbbox" id="sbbox" class="can" multiple>
<cfloop list="#lstFinds#" index="k" delimiters=",">
<option value="#k#" <cfif #listfindnocase(getproducts.ptype,k)#>selected</cfif>>#k#</option>
</cfloop>
</select></cfoutput>
When I run this code, abc, def, mon, and wed are selected. Should these not be selected, or should others be checked?
This code appears to be doing what you are asking. The only changes I made
Changed the logic as per what Matt suggested in question comments.
Because I don't have the data to run a query against, I setup a getProducts structure with the key "pType" and the values as Asker suggested they might be. For the purpose here, my sample struct is functionally identical to a one-row query.
Finally, is it possible that you're trying to pull this from multiple rows? You might try
<cfset variables.ptypes = valuelist(getproducts.ptype)>
<cfoutput><select name="sbbox" id="sbbox" class="can" multiple>
<cfloop list="#lstFinds#" index="k" delimiters=",">
<option value="#k#" <cfif #listfindnocase(variables.ptypes,k)#>selected</cfif>>#k#</option>
</cfloop>
</select></cfoutput>

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.

Including or excluding range attribute in dynamically generate form field

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#">

Need advice.. dynamic td tr

Hi am doing dynamic TR and TD in coldfusion, but apparently i am trying this kind of screen. here is my try with colfusion
<cfif variables.newrow EQ true>
<tr align="center">
</cfif>
<cfoutput query="gResults">
<cfquery datasource="#request.dsn#" name="nextqueries">
Query
</cfquery>
<td height="30" valign="middle"><strong>
<a href="viewdir.cfm?catID=#val(pic_id)#
<cfif isDefined('url.l') and url.l neq ''>&l=#url.l#</cfif>">
#pic_cat_name#</a></strong><br>
<cfloop query="nextqueries">
<cfquery datasource="#request.dsn#" name="showanother">
select * from
mytable as grlist
where pic_cid =
<cfqueryparam cfsqltype="cf_sql_numeric" value="#Trim(nextqueries.pic_id)">
</cfquery>
»
<a href="viewdir.cfm?catID=#val(pic_id)#
<cfif isDefined('url.l') and url.l neq ''>&l=#url.l#</cfif>">#pic_cat_name#
</a> </cfloop></td>
<cfif gResults.currentRow MOD 4 EQ 0>
</tr>
<cfset variables.newrow = true>
<cfelse>
<cfset variables.newrow = false>
</cfif>
</cfoutput>
trying to do like this:
http://screencast.com/t/oso4jkhBm3
There are a lot of potential improvements, but this answer will only deal with table rows. You start with:
<cfif variables.newrow EQ true>
<tr align="center">
</cfif>
Now I'm going to look for the closing tag. The only one I see is here:
<cfif gResults.currentRow MOD 4 EQ 0></tr></cfif>
and that line is inside a query loop. What this means is that you might have more than one closing tag, or you might not have any. You need exactly one. To solve this specific problem, you have to do this:
<cfif variables.newrow EQ true>
<tr align="center">
code to populate this table row
</cfif>
When you get that part sorted out, we can look at what goes into the details.
To get data to display in an html table from top to bottom then left to right like in the image linked in your question, you can do something similar to the following.
<!--- Get query results --->
<cfset arrayOFValues = arraynew(1)>
<cfset queryResults = querynew("Col1,Col2,Col3")>
<!--- Fill query with example data --->
<cfloop from="1" to="25" index="i">
<cfset queryaddrow(queryResults)>
<cfset querySetCell(queryResults, "Col1", "Col1 Row " & i)>
<cfset querySetCell(queryResults, "Col2", "Col1 Row " & i)>
<cfset querySetCell(queryResults, "Col3", "Col1 Row " & i)>
</cfloop>
<!--- Now have a query named queryResults with 25 rows --->
<!--- Set the number of columns and calculate the number of rows needed --->
<cfset numberOfColumns = 3>
<cfset rowsNeeded = ceiling(queryResults.recordcount / numberOfColumns)>
<cfoutput>
<table>
<cfloop from="1" to="#rowsNeeded#" index="curRow">
<tr>
<cfloop from="0" to="#numberOfColumns-1#" index="curCol">
<td>
#queryResults.Col1[(rowsNeeded * curCol) + curRow]#
</td>
</cfloop>
</tr>
</cfloop>
</table>
</cfoutput>
The first part is just creating a query result. I then find the number of rows that is needed to display the records by dividing the number of results returned in the query by the number of columns to be displayed. The ceiling is required for when the result is not a whole number.
We have to loop each column record with in the row to get the desired index. To find the required index of the field we have to take the row that’s being displayed + the column were on times the the number of rows that will be displayed.
If you know the number of columns you can hard code for them in the following manner and eliminate the inner loop.
<tr>
<td>#queryResults.Col1[3 * rowsNeeded]#</td>
<td>#queryResults.Col1[3 + 1*rowsNeeded]#</td>
<td>#queryResults.Col1[3 + 2*rowsNeeded]#</td>
</tr>