Posted in ColdFusion | Posted on 11-29-2006 | 8,788 views
Today there was a thread on cf-talk about how to make a "Loading" or "Please Wait" style page while ColdFusion is doing something slow. Most of the answers talked about AJAX but I thought I'd show a simpler version that just used a bit of JavaScript.
First I'll create my loading message:
2Please stand by while we do something.
3<cfoutput>#repeatString(" ", 250)#</cfoutput>
4</p>
Note that I gave an ID to my loading block. This will be used later. Also note the repeatString. Why do I have that? One of the "features" of IE is that it will not render any content until it gets "enough" content. I use this block of spaces simply to slap IE around and force it to render the content. My next line of code is a simple CFFLUSH:
This is what tells ColdFusion to send the current output back to the browser. Now for the slow code. Obviously this will be custom for your application, but for my test I just used some Java:
2<cfscript>
3go_to = createObject("java", "java.lang.Thread");
4go_to.sleep(3000); //sleep time in milliseconds
5</cfscript>
You can find this code on the ColdFusion Cookbook entry.
Now I just need to clean up the loading text. I used this simple JavaScript:
2loadingBlock = document.getElementById('loading');
3loadingBlock.style.display='none';
4</script>
And then I wrapped with a message to the user:
2Thanks for waiting. Here is your important information.
3</p>


Jay
(Do you hear thunder?)
I do not usually have the problem but I like the idea of a loading page sometimes. we pull huge quantities of data from databases and that can be slow at times so I appreciate the code.
Jay
M. McConnell
hour glass and all??
Jay
<script language="javaScript">
document.getElementById('loading').style.display='none';
</script>
@jay
You can get some nice animated waiting style images from
http://www.ajaxload.info
Using one of those, your page could be this:
<span id="loading">
<img src="ajax-loader.gif" alt="please wait">
</span>
<cfflush>
page stuff here
<script language="javaScript">
document.getElementById('loading').style.display='none';
</script>
Que serrar!
Jay
<head>
<script language="JavaScript" src="jscripts/xp_progress.js"></script>
</head>
<p id="loading">Page Loading - Please Wait...</p>
<script type="text/javascript">
var bar1= createBar (300,15,'white',1,'black','blue',85,7,3,"");
</script>
<cflush>
<script type="text/javascript">
setTimeout("document.getElementById('loading').style.display = 'none'", 2000);
setTimeout("bar1.hideBar()", 2000);
</script>
You can find more about xp_progress.js here:
http://www.dynamicdrive.com/dynamicindex11/xpprogr...
I long for the day when all of my family members have broadband. :)
You could also use the onload event, which would kick in once the entire page was loaded.
<script language="javascript">
window.onload = function(){
document.getElementById('loading').style.display='none';
}
</script>
What has been posted here has been great though.
Believe it or not I did this myself as well... in Perl... in 93 or so. ;)
Would using two GetTickCount functions to get the time it took to process the page do the trick? You could do it like this:
1. Put the first GetTickCount statement right after the <cfflush> and assign its value to a variable (say startTime).
2. Put the second GetTickCount statement at the end of your code and assign its value to a variable (endTime).
3. Subtract startTime from endTime and divide by 1000 to get the number of seconds it took to process the page.
4. Put a JavaScript block at the end of the code that writes that result to a <span> or <div> element at the top of the page (like “Load time: 83 seconds”).
Taking an easy example, if you have 4 queries to perform just CFLUSH some javascript after each CFQUERY to knock a visual counter on the page up by 25%. It will only be accurate if all queries take the same amount of time to process, so in reality the progress bar will show the percentage of CFML processed rather than a percentage of time to wait. If you only have 1 big query to do then obviously this idea won't help you.
or run a time and display it upon completion.
I have still not gotten the hang of making javascript show time as it loads so if anyone has a simple example it would be great.
I'd like to inject a twist into this whole issue, not specifically related to displaying loading messages, but rather to the underlying issue of long-running processes, especially as applied to Model-Glue. I've tossed this out on the MG list a couple of times, but without much response.
So -- you have a Model-Glue event that sets off a long-running process. One that runs long enough that it could possibly run into the default CF timeout (and you don't want to reset the default timeout on the installation just for this one process).
Where in the sequence of MG actions would you/could you place a CFSETTING timeout value that would prevent the process from timing out? And how would you set up an event structure that would allow for a "loading" message of some sort, as well as for some sort of check to see if the process were complete. Then, of course, the results would need to be displayed.
I'm well aware that I just massively overcomplicated this whole blog entry. But since you've been working with Model-Glue a lot lately, I'm hoping you (or someone else listening) might be able to provide a little guidance.
http://cfconcurrency.riaforge.org/
I don't think you could do the "please wait" as we did though. You could tell the view to reload using JS, after like 3 seconds, and have the controllers check and see if the concurrent event is done yet.
Thanks. But unfortunately, the site in question is running CF Standard, so the Asynchronous Gateway isn't available.
How about something like this (not my idea, suggested by someone smarter):
The originating event simply contains two result statements in its event-handler tag. One kicks off the long-running process. The second simply returns a view, which could contain a loading message.
The first event goes on its merry way -- can you put a CFSETTING tag in a CFC method? -- and when it's complete, sets a session variable.
In the view produced from the second event, there's an iframe or a refresh, or an AJAX call, or something, which fires an event which checks the status of that session variable. If the process is complete, a result tag fires a final event to show the results.
This sounds pretty close. But I think I'm missing something. And of course, I've gone way far afield from the original subject.
As far as the CFSCHEDULE suggestion goes: do you mean, use a CFSCHEDULE tag, scheduled to Now(), to call one of the events?
And -- one of the things I'm most confused about: where would I place a CFSETTING tag to avoid the long process from timing out? Can I simply place it in the method of the controller that's fired for the process, or perhaps in a global OnRequestStart method, applying the CFSETTING based on the name of the event?
I bring up the latter idea because in Mach-II, Peter Farrell has written a filter that can be applied to long-running events. If you apply the filter to an event and specify a timeout param, the CFSETTING appears to work throughout the event - or I guess, throughout the request. So I'm wondering if you could do much the same thing in MG,using an OnRequestStart method? Does any of that make sense?
Yes to your cfschedule thing.
CFSETTING: I'd place it in Application.cfm and make it global. You could also do it in the controller for the event in question.
Thanks for all your help.
As far as the sequence thing goes, what I was really asking (and I'll experiment to see the results on my own) was whether you could a) fire an event that simply announced two result; then b)the first resulting event would deliver some sort of "loading" view; and c) the second resulting event would actually call the long-running process. In that case, would MG render the loading view, then go on and start the process? If so, then it might be possible to check the progress of the event and deal with it.
Anyway, I'll play with it and see what happens. If I come up with anything useful, I'll share it.
Thanks again for your generous assistance.
I put this:
<span id="loading">
<img src="ajax-loader.gif" alt="please wait">
</span> <cfflush>
above all my long running queries to make it work. This puts it above my <html> tags. It seems to work just fine, but is this a bad idea?
Saw you at CFUnited last year. I hate that is is the last one. I can't come!
Raymond,Thanks for your prompt reply.
[Add Comment] [Subscribe to Comments]