Open-Source Review - AjaxCFC
The obvious first step is to download the AjaxCFC zip file. When you unzip it you will see the core files folder which contains ajax.cfc and the necessary javascript files, a documentation folder which includes the documentation pdf and an examples directory that contains about 9 different examples covering various uses for the tool. To be honest, I didn't even go through the examples, but what I was trying to accomplish ended up being straightforward enough that I didn't need to (though, perhaps, it would have saved me some time nonetheless).
The documentation is all of 6 pages, which, to be honest, seemed a little brief to me considering all that AjaxCFC can do, but in the end it did provide all the information I needed to get started (which is a tribute to how simple AjaxCFC is to use).
The Code
At the risk of purely repeating the documentation, the first thing you need to do is add the following includes to your document:
<script type='text/javascript'> _ajaxConfig = {'_cfscriptLocation':'com/ajax_cfoslist.cfc', '_jsscriptFolder':'js'}; </script>
<script type='text/javascript' src='js/ajax.js'>
</script>
The first script is my ColdFusion component location. You can alternately supply this with each call, but I am using only one, so it simplifies the later calls to specify this here. The second is the location of the provided javascripts directory. The second script is the primary JavaScript include.
Next let's take a look at my component:
<cfcomponent extends="ajax">
<cfset variables.reactor = CreateObject("Component","reactor.reactorFactory").init(expandPath("../reactor.xml")) />
<cffunction name="getResources" access="private" output="false" returntype="string">
<cfargument name="args" required="true" type="array" />
<cfset var qryResources = "" />
<cfset var rtnHTML = "">
<cfset var resourceGateway = variables.reactor.createGateway("opensourceresource") />
<!--- build a joined query of resources and resource categories --->
<cfset var objQry = resourceGateway.createQuery() />
<cfset objQry.join('opensourceresource','opensourceresourcecategories') />
<cfset objQry.join('opensourceresourceCategories','opensourcecategory') />
<cfset objQry.returnObjectFields("opensourceresource") />
<cfset objQry.returnObjectFields("opensourcecategory") />
<cfset objQry.getOrder().setAsc('opensourceresource','freeButNotOS')>
<cfset objQry.getOrder().setAsc('opensourceresource','title')>
<cfset objQry.getOrder().setAsc('opensourceresource','resourceID')>
<cfif arguments.args[1] NEQ "all">
<cfset objQry.getWhere().isEqual('opensourcecategory','categoryID',arguments.args[1]) />
</cfif>
<cfset qryResources = resourceGateway.getByQuery(objQry) />
<cfsavecontent variable="rtnHTML">
<cfif arguments.args[1] NEQ "all">
<cfoutput>
<p>
<strong>Viewing Category: #qryResources.category#</strong> - [<a href="rss.cfm?categoryID=#qryResources.category#">RSS</a>] - [<a href="##" onclick="getResources('all');">View All Records</a>]</p>
</cfoutput>
</cfif>
<cfoutput query="qryResources" group="resourceID">
<cfif qryResources.freeButNotOS EQ 1 AND qryResources.freeButNotOS[qryResources.currentRow -1] EQ 0>
<h3>Free But Not Open-Source</h3>
</cfif>
<div id="resource">
<p>
<span class="title">
<a href="#qryResources.href#">#qryResources.title#</a>
</span>
<cfif session.isLoggedIn> | <span class="edit">
<a href="edit.cfm?resourceID=#qryResources.resourceID#">edit</a>
</span>
</cfif>
<br />
<span class="description">#qryResources.description#</span>
<br />
<cfif len(qryResources.license)>
<span class="license">License: #qryResources.license#</span>
<br />
</cfif>
<span class="categories">Categories: <cfoutput group="categoryID">
<a href="##" onclick="getResources('#qryResources.categoryID#');">#qryResources.category#</a>
</cfoutput>
</span>
<p>
</div>
</cfoutput>
</cfsavecontent>
<cfreturn rtnHTML />
</cffunction>
</cfcomponent>
First, it is important to remember that all your AJAX components need to extend the ajax.cfc. Second, as I have covered before, my list application is running on that post as I am not going to go over it here). Third, my application did use the onRequest() method in the Application.cfc, so I needed to put a different (basically empty) Application.cfc in the folder where my AJAX components reside.
Originally, my one and only method returned a query. AjaxCFC has alot of great built in features to handle query data. However, in the end, it seemed easier to me to generate this content via CF than spend alot of time rewriting this code in JavaScript. In fact, this simply duplicates the output code on my cfm page - another note: I decided not to call this AJAX function to get the full list on document load because this would have been slower, totally unnecessary and (I believe though I am not certain) could have issues with search engines; the only issue with this is the fact that the output code ends up duplicated. In the end, this function is much simpler than it may appear as all it does it perform a query and generate the HTML from that query which is then returned. The one thing is that AjaxCFC passes all arguments in an arguments array, which is why I refer to arguments.args[1], which in this case is the category id.
In my list display page, I created a couple of scripts to handle the AJAX calls:
<script type="text/javascript"> function getResources(id) { document.getElementById('resourceList').innerHTML = '<div align="right">
<div style="width:100px;padding:3px;background-color:red;color:white;">loading...</div>
</div>'; DWREngine._execute(_ajaxConfig._cfscriptLocation,null,'getResources',writeList,id); } function writeList(result) { document.getElementById('resourceList').innerHTML =result; } </script>
The first script (getResources()) accepts the category id. The primary reason this script is necessary is to show some form of feedback to the user when they click a link (in the form of a loading box styled off gmail - surprise). That is what is occurring on the first line of this script. The second line is the AJAX call. The call passes the CF script location (which we defined earlier but could be defined explicitly here) as its first argument. The second argument (which is scriptName) is generally null. The third argument is the function to call within your cfc. The fourth argument is the JavaScript function to call when the data is returned. The last argument in this case is my category id argument. If I had more arguments to pass, I could continue to list these (and they would all be passed by the array). Strangely, in looking at my code I seem to have diverged from the documentation here as the docs show the arguments coming before the callback function - but weird...it works nonetheless.
The last script is very simple, it takes the returned result (a string) and sets the HTML of my DIV to the returned HTML.
So to call this I simply set the category links to:
<a href="##" onclick="getResources('#qryResources.categoryID#');">#qryResources.categoryName#</a>
That's it. Pretty simple right? Obviously there is alot more you can do with AjaxCFC, but hopefully this will serve as a decent introduction to AJAX newbies like myself. However, given its ease of implementation, I may delve into a little more AJAX in the future (trying hard not to overuse it as it is sometimes used purely for gimmick sake IMHO - and yes, the usage in the article is a little gimmicky, but the point was to learn :-)
Thanks for ANY help!

