I was wondering what I could do to improve the AJAXyness (yes, it is word, because I said so) of ColdFusionBloggers.org, and I came up with a cool trick. On the right hand side of the site is a stats pod. While the number of feeds won't change, and the number of entries won't change often, the number of users will go up and down. I wanted the information to update without user action and this is what I came up with. (As a note, the code attached to the zip is now old.)
First I took the block of code and moved it to a new file, stats.cfm. I then edited my layout page and changed the stats pod to this:
<cfdiv id="statsdiv" bind="url:stats.cfm">
</cfdiv>
The CFDIV is binding to a url, stats.cfm. Again, that's where I moved the stat text. So far so good. Next I added this to my body tag:
<body onload="window.setTimeout('updatestats()',60000)">
And added this JavaScript function:
<script>
function updatestats() {
ColdFusion.navigate('stats.cfm','statsdiv');
window.setTimeout('updatestats()',60000);
}
</script>
And that's it. Now when it loads you will get a loading grapic, as it is now for me, and I'm hoping it's just the flakey Airport wifi. (But I shouldn't complain, it's free.)
Thoughts?
Archived Comments
Try setInterval() instead of setTimeout() in your body tag. setInterval() executes the function every x period of time, eliminating the need for your function to handle re-executing itself.
Thanks Doug. I'll make the change. I've posted it back to the live site too. The funny thing about all this AJAX work lately is that my rusty JavaScript skills are slowly warming back up again. I remember the day the first build of Netscape with JavaScript was released. :)
If you use a JavaScript lib like Prototype.js, auto-refreshing could be much easier with something like the Ajax.PeriodicalUpdater. More info at http://prototypejs.org/api/.... I'm sure the underlaying Yahoo-UI has something similar.
I have to be honest, on _quick_ inspection, that doesn't look easier. It doesn't look much harder, but it doesn't look any easier to me. Just saying. ;) Also note my JS code got a bit smaller when I changed to setInterval. You know - I'm going to add a ER for CF to add a refresh attributes to div.
Ok, now it's a challenge, he he:
this is what you do with your current solution right:
<body onload="window.setTimeout('updatestats()',60000)">
<script>
function updatestats() {
ColdFusion.navigate('stats.cfm','statsdiv');
window.setTimeout('updatestats()',60000);
}
</script>
if you use prototype.js the code looks like this:
<script>
new Ajax.PeriodicalUpdater('statsdiv', 'stats.cfm', {
method: 'get', frequency: 3, decay: 2
});
</script>
Looks more concise and easier to me, but I could be partial.
I wouldn't say prototype.js makes it easier in this specific case, since Rays script is all of two lines of code.
The prototype Ajax.PeriodicalUpdater() IS rather handy, however. I particularly like the "decay" feature.
Doh, the above comment didn't seem to work with the code. Feel free to delete it. Trying again.
This is what you do with your current solution right:
<body onload="window.setTimeout('updatestats()',60000)">
<script>
function updatestats() {
ColdFusion.navigate('stats.cfm','statsdiv');
window.setTimeout('updatestats()',60000);
}
</script>
if you use prototype.js the code looks like this:
<script>
new Ajax.PeriodicalUpdater('statsdiv', 'stats.cfm', {
method: 'get', frequency: 3, decay: 2
});
</script>
If we are going for concise, I say this isn't bad (and doesn't require an additional library):
<body onload="window.setInterval(function(){ColdFusion.navigate('stats.cfm','statsdiv');},60000)">
Boyan - heh, well, with the CF8 one you don't need to include another library. I mean the end result is additional JS stuff, but in the CF8 one, its auto loaded. ;)
Is that library within CF8 always loaded or do you have to specify to load it? If I were to upgrade an existing site which uses Prototype or jQuery for instance to run on CF8, will I then be loading CF8's js and my own library?
CF only loads the JS libraries when it needs to. If you put an old site up on a cf8 box, it won't load anything new as you wouldn't be using any of the new tags.
I noticed that if I use a cfdiv for my main content and use ColdFusion.navigate to change the contents which are based on queries, if I navigate away, change the criteria and navigate back, the data is not requeried unless I manually refresh the cfdiv (by using a cfmenu navigate). is there a way to simply make sure you are re-executing the code on a page in a cfdiv that you are navigate-ing to?
Are you saying it is caching? If so - you can try simply navigating to a url with a random number at the end. I do that all the time in Spry for IE.
ok, so I have this index.cfm page with three cfdiv areas on it, header,menu and content. I use the cfmenu in the menu cfdiv to ColdFusion.navigate the changeCustomer form into the content cfdiv. I use an onclick event on a button to run a function (submitMe = function(){ColdFusion.Ajax.submitForm('frmChangeCustomer','/Admin/ChangeCustomerProcess.cfm');
ColdFusion.navigate('/Finished.cfm','content');
}
so it submits the form and updates the content cfdiv to show the finished page which runs two queries to get the new customer name and the new business unit and display them in an ordinary html table. Unfortunately, the old customer shows up like it never ran the queries. If I dump the session I can see that the form was submitted and the data saved and read into the session scope but it doesn't show up on the finished.cfm page
Did you try the random number like I said?
uh, no... how do you do that? (Dammit, I'm so ignorant!)
This is an example from Lighthouse Pro:
var dsIssues = new Spry.Data.JSONDataSet("issuesxml.cfm?id=#p.getID()#&stupid=#rand("SHA1PRNG")#",{path:"data", pathIsObjectOfArrays: true});
I am not sure how to use that but I tried this coldfusion rand function and it failed too:
<script language="javascript">
submitMe = function() {
ColdFusion.Ajax.submitForm('frmChangeCustomer','/Admin/ChangeCustomerProcess.cfm');
ColdFusion.navigate('/Finished.cfm?rn=<cfoutput>#Rand("SHA1PRNG")#</cfoutput>','content');
}
</script>
funny thing is, I have an employee form that I run using the same code and it works, the main difference is there are more pages to go through because there's a confirmation page. so I have a list I pick an employee by clicking on a ColdFusion.navigate link, that takes me to an edit form, I submit using a ColdFusion.Ajax.submitForm function that then navigates to a processing page and then to the confirmation page. the confirmationpage has a couple of buttons in a cfform that run another ColdFusion.navigate to take you to the page that actually saves the data to the database and then ColdFusion.navigates to the employee listing and by that time the employee listing shows the new record.
the submitForm and navigate function is in the edit form page. I always get the following error whenever the ColdFusion navigate function is in there:
ColdFusion.Ajax.checkImportedTag('CFFORM');
Of course on my main index page that contains the cfdiv tags, I have the following line near the top:
<cfajaximport tags="cfform, cfpod, cftextarea, cftooltip, cfwindow">
am i missing something?
Do you really have spaces? There should be no space in the list of tags.
took the spaces out, still no joy. since I am doing the cfajaximport on the "master" page and then using a cfform tag on the edit form, maybe there's some weirdness like "double" ajax library importing?
Here is what I am doing to make this work:
on the form:
I got rid of the javascript function in the head and changed the button back to cfinput type="submit"
now the form uses the intended cfform submit routines built in (stays in the same container)
on the processing page, I just use a cfinclude instead of navigating. since the processing page doesn't display anything, the user only sees the results page (or the source page)
I get no Ajax.checkImportedTag error and I can cfif which page to cfinclude and the best part is that the page contains updated results so the user can see the results of their changes immediately
I think I figured out the goofy checkImportedTag problem. I was putting the javascript in the head section (like I thought I was supposed to do) but when I moved the function inside the form the error went away and everything still worked.
So right after the cfform tag I have something like this:
<script>
callback = function(){
ColdFusion.navigate('/WorklogFinished.cfm','content');
}
</script
Hi there, can any one point me what's wrong with this form:
http://www.multilistmanager...
JS CODE:
-------------------
<script type="text/javascript">
function doSendContactAgent() {
ColdFusion.Ajax.submitForm('contactAgent', '/cfm/invokeForms.cfc?method=sendContactAgent', resultInsertHandler,insertErrorHandler);
}
function resultInsertHandler() {
var resultDiv = document.getElementById("result");
resultDiv.innerHTML = "<p>Employee Added.</p>";
}
function insertErrorHandler(id, message) {
alert("Error while updating\n Error code: "+id+"\n Message: "+message);
var resultDiv = document.getElementById("result");
resultDiv.innerHTML = "<p>Employee NOT Added.</p>";
}
</script>
FORM CODE:
-------------------
<cfform name="contactAgent" format="html">
<cfinput type="text" id="subjectid" name="subject" value="x" tabindex="1" disabled="yes">
<cfinput type="text" id="emailid" name="email" value="" tabindex="1">
<cfinput type="text" id="nameid" name="name" value="" tabindex="2">
<cfinput type="text" id="telephoneid" name="telephone" value="" tabindex="3">
<cftextarea id="commentsid" name="comments" rows="2" cols="5" tabindex="4" ></cftextarea>
<cfinput name="send" type="button" onClick="javascript:doSendContactAgent();" value="Send Info"/>
<cfinput name="send" type="reset" value="Reset"/>
</cfform>
invokeForms.cfc CODE:
-------------------
<cffunction name="sendContactAgent" access="remote">
<cfmail to="xerranomx@gmail.com" from="#form.name#" replyto="#form.email#" server="mail.multilistmanager.com" username="info.multilistmanager.com" password="info266" subject="WEB LEAD #form.subject#">
-----Message------
<cfmailparam name="X-Priority" value="1">
</cfmail>
</cffunction>
Thanks in advance guys
This is great, except I'm running CF 7 so I can't CF's native Ajax functionality. I'm trying to use Prototype's PeriodicalUpdater class, though, but I don't want to refresh the whole page, just one data point within it. I have the JS function working and all but I'm not sure how to make the data point (a column from the db) refresh. For example,
<div id="totalSales">#totalSales#</div>
but this value never seems to refresh.
TIA
Wish I could help you, but I only know Spry and a bit of jQuery.
I'm open to other libraries. I just need a way to refresh a data point within a page. I'm going to check to see whether Spry or jQuery provide this functionality.
I know Spry can do it - and jQuery is very powerful as well. I'd use Spry though - it's my personal favorite. :)
Do you know if its possible to do this without having the loading and icon show up? I tried to find a way around it but no luck...
Thanks
As far as I know, no. You can always do it manually in jquery of course.
Cool solution... maybe you can help me with an issue. I'm refreshing a cfdiv inside a cflayoutarea inside a cflayout type="tab". Everytime the div refreshes, it resizes the layout area, trimming the div until the div is no longer visible.
Can you use tabheight to set the height of the tab - that way it should stick to one value.
Thanks for replying. I did set the height to an actual value and that resolved the trim issue. I think it's related to another issue in that the cfdiv is not always displaying its contents (a cfgrid). Seems to be an IE6 issue only. I can't recreate in Firefox.
This is really good stuff, thanks again Ray.
Note: If your CFDIV is positioned at the bottom of your page you may need to provide it with a height in the CSS.
Otherwise scrolling can 'jump up' to what it thinks is the bottom of the page once the CFDIV has been refreshed.
Sam.
I'm a little lost here. I see how to refresh a DIV using the timer.
I'm building a shoutbox and i have it wrapped in a (div id="shoutbox"></div> tag. All that happens in the shoutbox is a query to grab the name, message, date. I have a link below the box that you click that launches a popup window using cfwindow. In the cfwindow is a form with a name field, message field, and a submit button. The date field is hidden. When you click the submit button is points to a script that insert the data into the database.
I'm using the Codlfusion.AJAX.submitform to submit the form. Now all I want to do is add some code to my JS function to refresh only that div after the script is run. Right now i think it keeps triggering before the submit happens because i keep getting errors the variable form.name isn't defined.
Anyone know a simple way to refresh a specific div based on an event. I don't want to keep refreshing and refreshing, that will be annoying.
Please could really use the help/
ooh, you are doing it right on this page. When i submit this is auto-refeshes, but its not on a timer. However you aren't using a modal window like i am trying to do.
So -- whats the secret?
I LOVE YOU! YOU ARE THE MAN FOR ME... If I was a women. But dude I want to thank you so so so so much. I was looking all over freaking town for something like this... YOU ARE A CFGOD
Just Kidding
Thanks A Million...
You are most welcome Jody.
Hmmmm....why is it that your code always works as described, the first time? I spent a lot of time on various sites trying to get this capability with jQuery and wasted 2 hours. Used the above and had what I needed in literally 30 seconds.
Thanks a zillion!!
The only reason my code works the first time is that I banged my head against the wall for a good hour beforehand. You guys see the sausage, not how it is made. :P You are welcome - glad to help!
Ray,
Thanks for this code. Years later and it's still helping people.
I do have a bit of an issue and I'm no sure why. I am setting the CFDIV to refresh every 10 seconds and occasionally I get an error stating one of the variables is not defined. Something like
"Error retrieving markup for element resultsDiv : Element KEYWORD is undefined in QRYKEYWORDCOUNT. Enable debugging..."
DO you know why this would be happening. I click ok on the pop up and the page loads just fine. I'm just randomly getting these messages. It's not the same variable each time either. Is the code loading too fast? Too often?
Ryan
Can you share (via Gist or Pastebin) the code that your div is hitting, and the calling page?
Thanks Ray.. wasn't sure if embedding worked or not, here is the code
https://gist.github.com/ano...
Nothing really stands out. Best I can suggest is a hell of a lot of debugging using cflog. For example, since the error above means keyword isn't a column, you can cflog the columnlist from the query object and see if it is weird. You can log pretty much everything.