ColdFusion TIPS PLUS
Issue 00081 http://www.cftipsplus.com
I. My CommentsII. ColdFusion In Context: Showing Progress
By R. Martin Ladner
martin.ladner@knology.net
In the Next Issue:ColdFusion In Context: Read Encrypted Files
I. Comments:
Unpacking boxes is no fun... Hope new things are around the corner...
Keep Coding,
Nathan Stanford
President/CEO
C.F. Concepts, Inc.
http://www.coldfusionmonthly.com
http://www.cftipsplus.com
If you have suggestions for articles send them to us.
If you would like to write for cftipsplus.com
send us an email to:
admin@cftipsplus.com
IF YOU WANT TO BE AN AUTHOR SEND IN YOUR COLDFUSION TIPS.
Remember this is a great way to get your name known in the
ColdFusion Community.
Advanced, Intensive ColdFusion Training!Visit this site. If you have plans to get training here is a company that provides Advanced, Intensive ColdFusion Training. Check them out.
http://www.coldfusiontraining.com/index.cfm?ref=cftipsplus
CFM - The ColdFusion Monthly!
http://www.ColdFusionMonthly.com
By becoming a .CFM subscriber, you'll receive. ColdFusion information you will not find anywhere else:
Tips, tricks, techniques, strategies, and a wealth of knowledge you will be able to apply immediately to your work, all from established developers.
Monthly access to new articles written by industry-leading ColdFusion experts. A fully-functional application that accompanies each issue.
Full access to all issues, past and present (with a one year paid subscription). The chance to be seen in our "Community Spotlight" corner, which showcases new writers and emerging talent
If you have any suggestions please email me at
cftips@nsnd.com.
II. ColdFusion in Context: Showing Progress
By R. Martin Ladner
martin.ladner@knology.net
Suppose you want to show your user a measure of progress toward a multi-step goal. Because ColdFusion waits to display any part of the page until the entire page is ready (assuming you don't have CF 5.0 and therefore can't use the cfflush tag), you usually have to display a separate page for each step.
However, you could do the work using a series of background pages while displaying progress in a form that's in a display page of the same frame; that's what this tip will demonstrate. Because the focus of this tip is on moving data between frames, you may want to check out a previous column if you want more information on the cfexecute tag used in this demonstration.
Start with Data
Here's a small text file for an external process to use for this demonstration. Paste it into a spreadsheet to generate a comma-separated values file named plant.csv. The tilde (~) at the beginning of each data line makes it easier to separate the wheat from the chaff later on.
SQ PERMIT FACILITY CITY
~ 32 AR0035459 USA-COE ALPINE RIDGE REC AREA ARKADELPHIA
~ 33 AR0036749 ARKADELPHIA HUMAN DEVELOPMENT ARKADELPHIA
~ 34 AR0035751 ARKANSAS CITY, CITY OF ARKANSAS CITY
~ 35 AR0046663 MG INDUSTRIES ARMOREL
~ 36 AR0045977 NUCOR STEEL - ARKANSAS ARMOREL
~ 37 AR0049166 IPSCO TUBULARS, INC. ARMOREL
~ 38 AR0046523 MAVERICK TUBE CORPORATION ARMOREL
~ 39 AR0041742 ASH FLAT, CITY OF ASH FLAT
~ 40 AR0049379 HANSON AGGREGATES WEST, INC. ASHDOWN
~ 41 AR0048411 DOMTAR A.W. CORPORATION ASHDOWN
Make a Display
To see the progress of several runs of this executable without leaving the current page, you need a display. This one uses the textarea tag for simplicity. The wrap attribute used here preserves linefeeds. Call this code show.cfm.
<form name="show" action="done.cfm">
<textarea name="report" wrap="physical" rows="4" cols="52">
</textarea>
<input type="submit" name="done" value="Continue">
</form>
Control the Executable
To execute an external process from ColdFusion, it's handy to wrap the external process in a batch file for control. The cfexecute tag only lets you pass a single argument and strips the double quotes from it. If you call a batch file instead of the raw executable, you can pass it multiple arguments (by creating the batch file on the fly if necessary). This example passes three parameters: an "i" flag to make the search case-insensitive, the string (in double quotes) to be searched for, and the name of the file to be searched. Name this file try.bat. (To avoid confusion, it should never have the same basic name as other executable files on your machine.)
find.exe /i "%1" c:\mydirectory\plant.csv
Call the Executable from ColdFusion
This general-purpose call to the batch file names the batch file and sends the search string from the page that calls this one to the batch file as a single argument. It has a default argument just in case. The pre tag preserves the linefeeds returned by the external program. The command is set to time out in two seconds; call this code find.cfm.
<cfparam name="Question" default="arkadelphia">
<pre>
<cfexecute
name="c:\mydirectory\try.bat"
arguments="#Question#"
timeout="2">
</cfexecute>
</pre>
Set Up a Custom Tag Environment
By using both the opening and closing tags of a custom tag, you can use it to capture text that would otherwise go to the screen (such as output generated by the cfexecute tag) and send it to a variable instead. ColdFusion automatically copies any output that occurs between an opening and closing tag to a variable named "ThisTag.GeneratedContent". Copy this data to a variable prefixed with the word "caller"; because, the page that called this tag can see any variable in the caller scope. Call this tag channel.cfm.
<cfset caller.Answer=ThisTag.GeneratedContent>
Create a Working Core
This code - call it core.cfm - gets and analyzes data. It silences the output of a custom tag, channel.cfm, that you've placed in this directory. This custom tag is wrapped around find.cfm. The cfloop tag then walks through the variable using a linefeed as the delimeter. Lines that begin with tilde (~) were selected because they match the search criteria and will increment the counter.
<cfsilent>
<cf_channel>
<cfinclude template="find.cfm">
</cf_channel>
</cfsilent>
<cfset Nr=0>
<cfloop list="#Answer#" index="line" delimiters="#chr(10)#">
<cfif left(trim(line),1) is "~">
<cfset Nr=Nr+1>
</cfif>
</cfloop>
Use it Multiple Times
This code - call it execute1.cfm - passes a question for the core code's response and sends the result to another page. Because this page will be in the same frameset as the display page, they can communicate with each other. When the page loads, it will read the value of the field named show from the form named report from the page the frameset calls display. It will then append a string containing its progress back to that same field. The String.fromCharCode() function represents a code as its corresponding character: a linefeed in this case. The self.location statement loads the next page. (The cflocation tag can't be used; because, then this page wouldn't write its output until the next page was done.)
<cfset Question="arkadelphia">
<cfinclude template="core.cfm">
<cfoutput>
#Answer#
</p>
<script language="javascript">
function doit() {
hold=parent.display.show.report.value;
parent.display.show.report.value=hold+'#Nr# match #Question#'+String.fromCharCode(10);
self.location="execute2.cfm";
}
</script>
</head><body bgcolor="999999" onLoad="doit()">
</cfoutput>
The second search is just like the first except that it looks for a different value and continues to a different page: call this search execute2.cfm.
<cfset Question="city">
<cfinclude template="core.cfm">
<cfoutput>
#Answer#
</p>
<script language="javascript">
function doit() {
hold=parent.display.show.report.value;
parent.display.show.report.value=hold+'#Nr# match #Question#'+String.fromCharCode(10);
self.location="execute3.cfm";
}
</script>
</head><body bgcolor="999999" onLoad="doit()">
</cfoutput>
Here's a third search: call it execute3.cfm. It doesn't go anywhere.
<cfset Question="arm">
<cfinclude template="core.cfm">
<cfoutput>
#Answer#
</p>
<script language="javascript">
function doit() {
hold=parent.display.show.report.value;
parent.display.show.report.value=hold+'#Nr# match #Question#'+String.fromCharCode(10);
}
</script>
</head><body bgcolor="999999" onLoad="doit()">
</cfoutput>
Build the Frameset
The final touch is a frameset that gives the display page all the window height except for a one-pixel line at the bottom of the window. Most users won't even notice the work page, and the noresize attribute will keep them from dragging it open. Call it framer.cfm.
<html><head>
<title>My App</title>
<!--- Place frameset BETWEEN head and body --->
</head>
<frameset rows="*,1">
<frame name="display" scrolling="auto" src="show.cfm">
<frame name="work" scrolling="no" noresize src="execute1.cfm">
</frameset>
<body>
<noframes>
Please use a browser that understands frames.
</noframes>
</body>
</html>
Use the Result
Copy these pages into a directory, customize try.bat and find.cfm to point to that directory, and browse framer.cfm. If you create a page named done.cfm, the "continue" button won't fail, and you'll have a complete example.
In this example, you've used a single display page to show the progress of a multi-step external process without having to refresh the display. See if this approach can be simplified, and then tell us about it.
=Marty=
Publisher and Creator:
Nathan Stanford,
admin@cftipsplus.com
C.F. Concepts, Inc.
http://www.cftipsplus.com
Macromedia and ColdFusion are U.S. registered trademarks.
Copyright (c) 2000 - 2001 C.F. Concepts, Inc.
CFTIPSPLUS.COM and NSND.COM
Permission is granted to circulate this publication via
MANUAL forwarding by email to friends provided that the text is
forwarded in its entirety and no fee is charged.