It must be something in the water. While I do not recommend using Application.cfc for header and footer layout, I've had two people in the last week ask me about this in terms of using Ajax. What they both found was that when they used Application.cfc to include a header and footer, this messed up their Ajax calls. Let's look at an example and show how we can quickly work around it.
First, here is a simple Application.cfc file that uses onRequestStart and onRequestEnd to output a header and footer:
<cfcomponent output="false">
<cfset this.name = "ApplicationName">
<cffunction name="onApplicationStart" returnType="boolean" output="false">
<cfreturn true>
</cffunction>
<cffunction name="onRequestStart" returnType="boolean" output="true">
<cfargument name="thePage" type="string" required="true">
<cfinclude template="header.cfm">
<cfreturn true>
</cffunction>
<cffunction name="onRequestEnd" returnType="void" output="true">
<cfargument name="thePage" type="string" required="true">
<cfinclude template="footer.cfm">
</cffunction>
</cfcomponent>
Here is my header.cfm and footer.cfm files respectively:
<html>
<head>
<title></title>
</head>
<!-- yes, pink, got a problem with that? -->
<body bgcolor="pink">
<p>
Copyright <cfoutput>#year(now())#</cfoutput>
</p>
</body>
</html>
Ok, so now for the interesting part - the Ajax application. This is a rather contrived example, but the code here will take a number and generate an array with that many elements. Each array item will have a random number in it. The code uses jQuery, but obviously the issue relates to Ajax in general.
<script src="jquery/jquery.js"></script>
<script>
$(document).ready(function() {
$.ajaxSetup({
error:function(req,textstatus,error) {
alert('e')
}
})
$("#submitBtn").click(function() {
var value = $("#number").val()
console.log('About to run my request...')
$.getJSON("test.cfc?method=makearr&returnFormat=json",{number:value},function(d) {
var res = ""
for(var i=0; i<d.length;i++) {
res += "item "+(i+1)+" is "+d[i]+"<br/>"
}
$("#result").html(res)
console.log('Done with request')
})
})
})
</script>
<input type="text" id="number"> <input type="submit" id="submitBtn" value="Double">
<div id="result"></div>
And finally, the last piece, the CFC:
<cfcomponent output="false">
<cffunction name="makearr" access="remote" returnType="array" output="false" secureJSON="false">
<cfargument name="number" required="true" type="any">
<cfset var arr = []>
<cfset var x = "">
<cfloop index="x" from="1" to="#arguments.number#">
<cfset arr[x] = randRange(1,100)>
</cfloop>
<cfreturn arr>
</cffunction>
</cfcomponent>
Ok, so hopefully I haven't lost you yet. If you run this, the result will be... nothing. Why? If you use Firebug to examine the result (and you would, right?), you can see the following:
Notice the JSON in the middle, wrapped by HTML? That HTML breaks the JSON format and prevents the front end code from correctly parsing it.
The best fix, in my opinion, is to get rid of the includes in Application.cfc. I'd use custom tag wrappers instead. But if you really want to keep them in, you can simply examine the requested template. Don't forget ColdFusion passes it to both the onRequestStart and End methods. Consider these new versions:
<cffunction name="onRequestStart" returnType="boolean" output="true">
<cfargument name="thePage" type="string" required="true">
<cfif listLast(arguments.thePage,".") neq "cfc">
<cfinclude template="header.cfm">
</cfif>
<cfreturn true>
</cffunction>
<cffunction name="onRequestEnd" returnType="void" output="true">
<cfargument name="thePage" type="string" required="true">
<cfif listLast(arguments.thePage,".") neq "cfc">
<cfinclude template="footer.cfm">
</cfif>
</cffunction>
In each method, I've wrapped the include with a simple check to see if the requested page ends with cfc. Hope this helps.