Mashing Spry Effects With CF8 Ajax Goodness
I'm working on an application that needed to give users the ability to subscribe/unsubscribe to certain elements. Rather then the boring old method I decided to try something new. Here were my requirements:
- Subscribe/Unsubscribe Without Page Refresh
- Add some funk to it
Pretty simple stuff. I decided I would take advantage of some of the built in Ajax features in CF 8 to take care of the async subscription activity. For the 'funk' I decided to take a look at Spry Effects - specifically a Fade effect to have the links slowly fade in/fade out depending on what was going on.
A greatly simplified version of the end result is here.
So let's take a look at a bit of the code. I begin by importing the SpryEffects.js and a cfajaximport (with no tags) to import the ColdFusion Ajax libraries.
<script src="SpryEffects.js"></script>
Next let's take a look at the display we're going to be using.
<span id="span1">content1</span>
<span id="span3">content3</span>
<!---
this next span displays the link to the user
it will be used to swap out the links later
--->
<span id="subUnsub">
<a href="javascript:subscribeHandler('sub');">Subscribe</a>
</span>
<!--- a hidden span holds our two options --->
<span id="sub" style="display:none;">
<a href="javascript:subscribeHandler('sub');">Subscribe</a>
</span>
<span id="unsub" style="display:none; width:100px;">
<a href="javascript:subscribeHandler('unsub');">Unsubscribe</a>
</span>
<!---
results div is used to hold the
contents of the ajax call's response.
in production i would hide this.
--->
<span id="results"></span>
So first I have a few filler spans just for fun. Next I have a single span that is going to be used to show the link to the user. Obviously you could conditionally decide which link to show to the user on page load - if they're currently subscribed you'd want to default to the unsubscribe link. Next there are two hidden spans (display: none;) which hold the actual HTML that is going to be swapped in and out of the displayed span. Finally there is a results span that holds the response from the Async call we'll make. Personally I'd hide that in production too.
Now lets look at some of the JavaScript required to facilitate the Async call and the fading effects.
var action = '';
fadeIn = function(){
var source = "";
if(action == 'sub'){
source = 'unsub';
}
else{
source = 'sub';
}
try{
var target = document.getElementById('subUnsub');
var source = document.getElementById(source);
target.innerHTML = source.innerHTML;
}
catch(e){}
var fadeI = new Spry.Effect.Fade('subUnsub',{duration:1000, from: 0, to: 100});
fadeI.start();
}
fadeOut = function(){
var fadeO = new Spry.Effect.Fade('subUnsub',{duration:1000, from: 100, to: 0, finish:fadeIn});
fadeO.start();
}
subCB = function(){
fadeOut();
}
subEH =function(eCode,eMsg){
//do nothing for now... }
subscribeHandler = function(a){
//global var to be used in the callback to determine what needs to fade action = a;
ColdFusion.navigate('sub.cfm?action='+action, 'results', subCB, subEH);
}
</script>
A lot going on, but essentially the subscribeHandler function kicks off the whole process. It makes an async call to sub.cfm (which currently just checks the url.action and returns a friendly message). I've specified a callback (subCB) and error handler (subEH) here in the ColdFusion.navigate() call. As you likely know these are functions that will be called when the HTTP response is finished. The one thing I do here is set the value of the global variable 'action' to whichever action has been passed to the function (subscribe or unsubscribe). This is used later to determine what needs to fade in/out.
My callback here looks like this:
fadeOut();
}
Really just a place holder. You could tecnically just make the straight call to fadeOut(). Here is fadeOut():
var fadeO = new Spry.Effect.Fade('subUnsub',{duration:1000, from: 100, to: 0, finish:fadeIn});
fadeO.start();
}
Here we use the Spry fade effect to hide the display span. We again utilize a callback function to call the fadeIn function when the fade is done (finish:fadeIn). The fadeIn function is where the content gets swapped out:
var source = "";
if(action == 'sub'){
source = 'unsub';
}
else{
source = 'sub';
}
try{
var target = document.getElementById('subUnsub');
var source = document.getElementById(source);
target.innerHTML = source.innerHTML;
}
catch(e){}
var fadeI = new Spry.Effect.Fade('subUnsub',{duration:1000, from: 0, to: 100});
fadeI.start();
}
So this checks the current value of the global 'action' variable that we set in the first call. Depending on that value we swap out the display container's innerHTML with the appropriate opposite action. Then we simply fade the display container back into view and voila.




<script type="text/javascript" charset='utf-8'>
function CF_RunContent(src){
try {
co = document.getElementById('chartOutput');
co.innerHTML = src;
//document.write(src);
} catch (err) {
txt="There was an error on this page.\n\n";
txt+="Error description: " + err.description + "\n\n" + err.message;
alert(txt);
}
}
</script>
My templates are like so:
index.cfm has cflayoutarea src="tabcontent.cfm"
tabContent.cfm has a cfgrid and cfdiv
and an empty <div id = "chartOutput"></div>
the cfdiv src file has cfchart and the javascript above. IE sucks and can't find /CFIDE/scripts no matter what I do so I hard coded the JS and it worked.
1.My main template constructs cflayout with north, west, south, and center defined.
2.Onajaxload, uses javascript to:
loadWorkQueueContainer = function() {
ColdFusion.navigate('spry_panel.cfm','main_area');
}
..where spy_panel.cfm is an html snippet made up of ....
<cfoutput>
<div id="Accordion1" class="Accordion">
<div class="AccordionPanel">
<div class="AccordionPanelTab">Callbacks</div>
<div id="callback_area" class="AccordionPanelContent">
</div>
</div>
<div class="AccordionPanel">
<div class="AccordionPanelTab">CBJB Candidates</div>
<div id="cbjbcandidate_area" class="AccordionPanelContent">
</div>
</div>
<div class="AccordionPanel">
<div class="AccordionPanelTab">CBJB Applicants</div>
<div id="cbjbapplicant_area" class="AccordionPanelContent">
</div>
</div>
</div>
</cfoutput>
<cfscript>
Ajaxonload("loadAccordion");
</cfscript>
3.loadAccordion looks like this...
loadAccordion = function()
{
var Accordion1 = new Spry.Widget.Accordion('Accordion1');
ColdFusion.navigate('workqueue/cbjbapplicant.cfm' 'cbjbapplicant_area');
ColdFusion.navigate('workqueue/cbjbcandidate.cfm' 'cbjbcandidate_area');
ColdFusion.navigate('workqueue/callback.cfm','callback_area');
}
NOTE: the above 3 cfm templates loads cfgrids.
MAIN ISSUE
Only the first panel display the cfgrid page navigation. THe other 2 containing panels seem to chop/hide the bottom cfgrid navigation. I tried swapping the cfgrids. Each time only the first panel renders properly.
If only CF8 used Ext JS 2.2, then I could use the Ext.layout.accordian.
Cheers!