Posted in JavaScript, ColdFusion | Posted on 05-20-2009 | 5,155 views
As yet another followup to my blog entry on CFTHREAD, a user asked about how to present a 'Please stand by' type message while the threads were running. This is fairly trivial with JavaScript and CFFLUSH:
2<cfloop index="x" from="1" to="5">
3 <cfset name = "find more cowbell #x#">
4 <cfset threadlist = listAppend(threadlist, name)>
5 <cfthread name="#name#">
6 <cfset sleep(3000)>
7 <cflog file="tdemo" text="All done with #thread.name#, baby.">
8 </cfthread>
9</cfloop>
10
11<cfoutput>
12<span id="loader">
13#repeatString(" ",250)#
14Please stand by...
15</span>
16</cfoutput>
17<cfflush>
18
19<cfthread action="join" name="#threadlist#" />
20<script>
21document.getElementById('loader').innerHTML = ''
22</script>
23
24<cfdump var="#cfthread#">
This is a slightly modified version of my previous code entry. Notice that I've added a span called loader with a bit of HTML. (The white space in front is to ensure IE renders the text.) After the cfthread/join action, I then use a bit more JavaScript to get rid of the loader. That's it. I'd normally use jQuery and some fancy loading graphic (like a unicorn, a magical unicorn), but hopefully you get the idea.


Hmmm. Now I have to find out what CFFLUSH does. You know it is amazing that I've worked with CF since version 4. Done amazing things with it. And I still keep finding things I have no clue about. I wonder if it is because I'm always under deadlines and rarely have time just to play with it? I find this stuff when I have a problem. Good thing there are people who have that time whose brains I can tap.
* Using any of the following tags or functions on a page anywhere after the cfflush tag can cause errors or unexpected results: cfcontent, cfcookie, cfform, cfheader, cfhtmlhead, cflocation, and SetLocale. Similarly, do not use any tags that use AJAX features, including cfdiv, cflayout, cflayoutarea, cfpod, cfsprydataset, cftooltip, cfwindow, or HTML format cfgrid, cftree, cftextarea, or cfinput (using autosuggest or datefield attributes) tags. All of the preceding tags and functions normally modify the HTML header, but cannot do so after a cfflush tag, because the cfflush sends the header.
* Using the cfset tag to set a cookie anywhere on a page that has a cfflush tag does not set the cookie in the browser.
* Using the cfflush tag in the body of several tags, including cfsavecontent, cfquery, and custom tags, causes errors.
* If you save Client variables as cookies, any client variables that you set after a cfflush tag are not saved in the browser.
* Using any of the following tags or functions on a page anywhere after the cfflush tag can cause errors or unexpected results: cfcontent, cfcookie, cfform, cfheader, cfhtmlhead, cflocation, and SetLocale. Similarly, do not use any tags that use AJAX features, including cfdiv, cflayout, cflayoutarea, cfpod, cfsprydataset, cftooltip, cfwindow, or HTML format cfgrid, cftree, cftextarea, or cfinput (using autosuggest or datefield attributes) tags. All of the preceding tags and functions normally modify the HTML header, but cannot do so after a cfflush tag, because the cfflush sends the header.
* Using the cfset tag to set a cookie anywhere on a page that has a cfflush tag does not set the cookie in the browser.
* Using the cfflush tag in the body of several tags, including cfsavecontent, cfquery, and custom tags, causes errors.
* If you save Client variables as cookies, any client variables that you set after a cfflush tag are not saved in the browser.
http://www.coldfusionjedi.com/index.cfm/2009/5/10/...
Or can it store the data and have it ready when I am?
Maybe I should just go test this. Like can I create a session variable that holds the query and then periodically check and see if that variable exists and when it does, use it?
I have a page which submits form data to a CF page that does quite a bit of processing before it loads the HTML portion of the page. Using your example, everything seems to work as expected with one issue. A variable that I create within the first thread doesn't seem to be available in the page thread (just after I join them). Even if I prefix the variable with the thread name, I still get an error: "Element X is undefined in THREAD". The way I read the CF8 documentation, it says that the page thread can access other threads on the page by using the prefix...am I reading this incorrectly? Thanks!
I think I actually figured it out after some trial and error. I was prefixing the variable with my thread name. When I changed it to THREAD.variable and then accessed it in the page thread as THREAD.variable it worked! For some reason, myThreadName.variable didn't seem to work...but it could have been that my head was so deep in the code that I wasn't referencing it correctly down the page. Anyhow, thanks for the super quick response, and thanks for this post..it did exactly what I needed!
sorry for digging that deep in time ...
Just checked your code here and it does not seems to work for me (FFox 3.612 / CF 8,0,1,195765).
I highly suspect <cfflush> ... but not certain of this.
Is there any other way to display main page message (or animated image) while thread(s) is (are) executing ?
For what I've tried now, we have to wait until threads have finished to display the page, wether they are named or not.
Sorry again for upping that *old* subject,
best regards,
A.
And finally, I may suggest one thing, based on binded cfc.
I'm not sure I'm not going nowhere but in the wrong direction, anyway I couldn't leave my screen as is.
First, I create a quite simple cfc :
[code]
<cfcomponent>
<cffunction name="sendmail" access="remote" output="false">
<cfargument name="numberOfIt" displayname="nb" hint="nb of iterations we call in the bind" type="numeric" default="10" required="no" />
<cfargument name="Speed" displayname="speed" hint="speed interval in millisecs we call in the bind" type="numeric" default="20" required="no" />
<cfloop from="1" to="#numberOfIt#" index="nbbs">
<cflog file="ABdemo" text="This is mail #nbbs# #timeformat(now(),"long")#">
<cfscript>
sleep(Speed);
</cfscript>
</cfloop>
<cfreturn "It's over now !"/>
</cffunction>
</cfcomponent>
[/code]
The tip is both here and in the form page; in fact we will only update the form field value ... providing start (default value of the field) and end (cfc returned value) texts.
Now, I set a very simple <cfform> page :
<head>
</head>
<body>
<cfform>
<cfinput type="text" value="Starting, please wait ..." bind="cfc:threadedMail.sendmail(5,100)" bindonload="yes" name="CFCstatus" id="CFCstatus">
<!--- The hint is here : default value will display first before CFC's finishes to run the code --->
</cfform>
</body>
</html>
Et voilĂ ... but just for start and end. Because - as much of you know (I didn't) - firing a <cfresult> is causing the function to stop, so that only first iteration of the loop would be ran.
Many questions still remain ...
1/ Is this method "load safe", or even "clean"
2/ Should I prefer to use <cfthread action="sleep" duration="Speed"> instead of CFScript sleep(Speed) ?
3/ Based on bind capabilities, I'll be surprised if none of you could find a workaround to update the CFCStatus field while in the loop
4/ And finaly, as my final goal is to use this to slow down CFmail campaigns, by grouping and slow down the send process ... how do you think this will fit my needs ?
Sorry for my froggy English,
Thanks in advance for any suggestion.
Antoine.
To your second reply: First off, I think doing it via Ajax is _better_. My code above is cool for simple stuff, but handing it off to an Ajax request gives you more control. Therefore - it's safe in my regards. Is it "load safe" - well that depends. If I reload your page many times it will keep making the Ajax request many times. You want to ensure your process _knows_ that it started and doesn't start off again. The code you have above will not do that.
You almost NEVER want to sleep. I used sleep just for demonstrative purposes. It was a way to make things slow on purpose. There are real needs for it, but generally, you should not be using it.
3) I'd just switch to using a jQuery solution. :)
4) oh! So then you may indeed want to use sleep. :) So yeah, I can see that making sense for you.
Should I post here modified code (I mean with some Thread control script) ?
[Add Comment] [Subscribe to Comments]