Next Page, for data editing - coldfusion

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.

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>

Coldfusion Word Document Table - Keep With Next

I am building a report that outputs the information into a word document using Coldfusion. Some of the information is output into tables and occasionally the table is occurring at the bottom of a page and the table ends up breaking apart to two pages. How do I keep the table from breaking apart?
The format is .doc.
<cfsavecontent variable="myDocument">
<html xmlns:w="urn:schemas-microsoft-com:office:word">
<head>
<xml>
<w:WordDocument>
<w:View>Print</w:View>
<w:Zoom>100</w:Zoom>
<w:DoNotOptimizeForBrowser/>
</w:WordDocument>
</xml>
</head>
<body>
<!--- run some queries to get information --->
<!--- Display some information via normal <cfoutput> --->
<!--- Then display information in table like this --->
<cfset xtest_count = 0>
<cfloop query="test">
<cfif xtest_count eq 0>
<cfset xtest_count = xtest_count + 1>
<b><u>Speaker<cfif test.recordcount gt 1>s</cfif></u></b><br><br>
<table width="100%" cellpadding=3 cellspacing=2 border=1>
<tr>
<td><b>Title</b></td>
<td><b>Name</b></td>
<td><b>Credentials</b></td>
<td><b>Organization</b></td>
</tr>
</cfif>
<tr>
<td>#test.title#</td>
<td nowrap>#test.first_name# #test.last_name#</td>
<td>#test.credentials#</td>
<td>#test.company_name#</td>
</tr>
</cfloop>
</table>
<!--- Display More information--->
</body>
</html>
</cfsavecontent>

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

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.

cfdocument prevent page breaks mid-row

I know this has been asked before but the solutions are from 2.5+ years ago so I'm asking if anyone has devised or knows of a more elegant solution to the problem using CF9. Can anyone confirm if CF10 supports the "page-break-inside: avoid" rule?
How can I prevent page-break in CFDocument from occuring in middle of content?
COLDFUSION: cfdocument and forcing a pagebreak
This is pretty much how I'm doing it. I've estimated, depending on what type of page it is, I can fit 9 or 11 rows of data before having to force a page break. Of course this is prone to breaking so if anyone knows of any evolution of the solution I would be grateful.
I believe I have found a pseudo solution. It is basically just what I said in the comments above. I take a best guess and see if it fits using the value of cfpdf's getInfo.totalPages. If it fits, great, merge it to the final document, if it doesn't, try again with one less row.
The downside to doing it this way is that it slows it down a bit and you can't use some of the stuff cfdocument makes easy like like messing with headers and footers. That being said, part 2 of this solution may be to record the number of rows that fit on a page in an array instead of merging the pages and rebuild the entire document again using cfdocument and those values as the loop constraints forcing a page break after. As it is, the below solution is already a little time consuming so building it again inside of a cfdocument tag may not work in high traffic sites.
Bug workaround: It looks like there is a bug with cfdocument that removes the background colors when saving the document to memory with the name attribute. The workaround is to remove the cfdocument tag to an external file. I saw one programmer placed it into a cfc, I found it's possible to use a simple cfinclude.
I hope someone finds this helpful, and if you know a better way to do this please comment.
<cfset reviewText = "Lorem ipsum dolor sit amet, + lots of characters.">
<cfset estimatedRowsPerPage = 7> <!--- This is the max number of records you want to try on each page. The larger the gap between max and actual will slow down the process. Used to reset attemptedRowsPerPage if the value changes --->
<cfset attemptedRowsPerPage = estimatedRowsPerPage> <!---- number of rows attempted to add to the page --->
<cfset totalRowsOutput = 0><!--- this is the number of records successfully saved to the final PDF --->
<cfset recordCount = 20> <!--- this is the query's record count --->
<!--- cfpdf cannot create a file from scratch and cfdocument requires some content so a container object cannot be created without at least one page. This page will be deleted later --->
<cfdocument format="pdf" marginbottom=".25" margintop=".25" marginleft=".25" marginright=".25" name = "finalDocument">Delete me</cfdocument>
<cfloop condition="totalRowsOutput lt recordCount">
<!--- create what *should* be a single page document --->
<cfdocument format="pdf" marginbottom=".25" margintop=".25" marginleft=".25" marginright=".25" name = "testDocument">
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>A title</title>
</head>
<body>
<table border="1">
<tr>
<td>Row:</td>
<td>Title:</td>
<td>Author:</td>
<td>Price:</td>
<td>Average Rating:</td>
<td>Reviews:</td>
</tr>
<cfoutput>
<cfloop from = "1" to = "#attemptedRowsPerPage#" index = "i">
<tr>
<td>
#i#
</td>
<td nowrap="nowrap">
#mid(reviewText,1,randRange(4,10))#
</td>
<td nowrap="nowrap">
#mid(reviewText,20,randRange(8,20))#
</td>
<td>
$10.00
</td>
<td>
#randRange(1,5)#
</td>
<td>
#mid(reviewText,1,randRange(10,700))#
</td>
</tr>
</cfloop>
</cfoutput>
</table>
</body>
</html>
</cfdocument>
<!--- get the document info to see if the page count = 1 --->
<cfpdf action="getinfo" source="testDocument" name="testInfo">
<cfif testInfo.totalPages gt 1>
<!--- if the page count is greater than 1 we need to try again with one less record. --->
<cfset attemptedRowsPerPage -= 1>
<cfelse>
<!--- merge the new single page to the final document --->
<cfpdf action = "merge" name = "finalDocument">
<cfpdfparam source="finalDocument">
<cfpdfparam source="testDocument">
</cfpdf>
<cfset totalRowsOutput += attemptedRowsPerPage>
<!--- if the page count = 1, we need to increment the startAttempt and reset the attemptedRowsPerPage unless attemptedRowsPerPage = recordCount --->
<cfif totalRowsOutput lt recordCount>
<!--- don't try to output more than exist --->
<cfset attemptedRowsPerPage = estimatedRowsPerPage+totalRowsOutput lt recordCount ? estimatedRowsPerPage : recordCount-totalRowsOutput>
</cfif>
</cfif>
</cfloop>
<!--- delete the manditory page needed to create our final document --->
<cfpdf action="deletePages" pages="1" source="finalDocument" name="finalDocument">
<!--- see "http://www.raymondcamden.com/index.cfm/2007/7/12/ColdFusion-8-Working-with-PDFs--A-Problem" to see why you need toBinary --->
<cfcontent type="application/pdf" variable="#toBinary(finalDocument)#">
Travis - I don't know of another way to do this. Usually I create an HTML table as the core of each "page" and have a specific number of rows before I close the table, break the page and open a new table.