ColdBox-Ajax Integration Guide
There are several techniques and ways you can integrate ColdBox with any Ajax library, either to return xml/json/wddx or html snippets (views). The best example for coldbox-ajax integration is the ColdBox Reader Sample Application by Oscar Arevalo and the CF8Ajax sample application by Sana Ullah and myself. It is very rich with Ajax techniques and renderings. This guide shows some tips and tricks on how to integrate ajax to coldbox applications. There are no limitations on what javascript libraries you use, they all work as long as ajax requests are made.
Overview
You can decide to return any type of data back to the caller via rendering json/wddx or actual html blocks. ColdBox can do all of these return types natively and you don't even need to know how to marshall (convert) the data; ColdBox will do it for you if so needed. So let's start by using the simplest form of Ajax integration: returning html snippets.
Returning HTML
HTML renderings is easy because that is what ColdBox does in its MVC core, render HTML. So to do a simple ajax call to the framework, you just call it as if you where doing it from the browser and requesting an event. The framework receives the request, process it, a view gets rendered and the ajax call receives the HTML snippet and you can div replace it anywhere you want.
Example
I have an event called: ehBlog.dspEntry that renders the vwEntry.cfm template. So in a typical call I would just call it as:
http://myapp/index.cfm?ehBlog.dspEntry&entry_id=1234
When you call it from an AJAX enabled application, you would do the exact same thing, either POST/GET to the above URL and the received content (HTML) div replaced wherever you want. And that is IT!! Easy right!! Below is a sample function using jquery that can proxy events as GET's or POSTS' and a simple call.
<script language="javascript"> function doEvent (e, targetID, params, methodType, onComplete ) { //set event var pars = "event=" + e + "&"; //Check for Method, else default to GET var methodType = (methodType == null) ? "GET" : methodType; //onComplete Handler Callback var onComplete = (onComplete == null) ? h_onComplete : onComplete; //parse params for(p in params) pars = pars + p + "=" + escape(params[p]) + "&"; //do Ajax Updater $.ajax( {type: methodType, url:"index.cfm", dataType:"html", data: pars, error: h_callError, complete: h_onComplete, success: function(req){ //Div Replacement HERE!! $("#"+targetID).html(req)} }); } //Form Event, this takes care of serializing a FORM. function doFormEvent (e, targetID, frm) { var params = {}; for(i=0;i<frm.length;i++) { if(!(frm[i].type=="radio" && !frm[i].checked) && frm[i].value != undefined) { params[frm[i].name] = frm[i].value; } } //Call event as POST doEvent(e, targetID, params, "POST"); } //A simple call: event, targetDIVID, params, methodType, onComplete call back doEvent('users.list','contentDiv', {active:true} ); //A Form Submission doFormEvent('users.save','contentDiv',document.updateForm); </script>
I am pretty sure that there are better ways to do the functions that I did above. These are some that I have used before and haven't updated in a while, because they do the job just right. They are for JQuery, but you can easily translate to any js library you want. The important lesson here is not the implementation but the actual idea of it.
Ajax HTML Layout
An ajax HTML layout would apply if you are returning simple html snippets and you want control on how they ALL return and look. However, this is optional because you can set a view to be rendered without any layout by using the following:
<cfset event.setView(name='vwEntry',nolayout=true)>
If you do this when returning html snippets, you do not need a layout, the view will be rendered and returned. However, layouts can be extremely useful as you will see below. I usually create a default layout for my ajax applications that take care of certain cleanup of the returned messages or if you want, you can create a specific layout for a specific folder. Below is how to do it.
In the configuration file:
<Layouts> <!-- The default layout is an ajax layout--> <DefaultLayout>Layout.Ajax.cfm</DefaultLayout> </Layouts> <!-- For a Folder --> <Layouts> <Layout name="ajax" file="Layout.Ajax.cfm"> <Folder>ajaxviews</Folder> </Layout> </Layouts>
The actual Layout.Ajax.cfm
<!--- Remove CF Output ---> <cfsetting showdebugoutput="false"> <!--- Remove the COldBox Debugger ---> <cfset event.showdebugpanel("false")> <!--- Render a messagebox, just for kicks ---> <cfset WriteOutput(getPlugin("messageBox").renderit())> <!--- Render the set View ---> <cfset WriteOutput(renderView())>
The first thing I do is remove the coldfusion debugging if available. Then I use the special magic function in the event object to disable the coldbox debugger: event.showdebugpanel( boolean ). Then I just output a messagebox if available and then I output my view to be rendered. That's it. The interesting methods here are that I tell coldbox to remove the debugger panel if I am in debugging mode. This layout is then used to render any view that is brought via Ajax. This opens a world of ideas on how it can be so flexible for your view renderings.
Returning DATA (xml/JSON/wddx/ANY)
ColdBox 2.6 introduces the new method called event.renderData() that was built specifically for you to interact remotely with the framework and return data. Below is the method signature of this great method:
- renderData(string type, any data, [string contenttype]);
Arguments
| argument | type | required | default | description |
| type | string | false | plain | The return type of the data. Available types are JSON, WDDX and PLAIN. The framework will take care of data marshalling for JSON and WDDX, plain means you will be doing the data conversion if necessary. |
| data | any | true | --- | The data structure to return. This can be anything except cfc's. |
| contentType | string | false | text/html | The content type to send to the browser. You can choose anything you want. If JSON type is used, the method will switch to text/plain. If WDDX is used, the method will switch to text/xml. |
The purpose of this method is for you to set the data to return, how to marshall or convert it and what type it is. The framework will then take care of everything for you, no need to abort the request or set a view or layout. The framework morphs into a remote framework. So not only can a call be done to the framework via the index.cfm but also by using the coldbox proxy. This method works with both calls. For more information on the coldbox proxy, please read the Coldbox Proxy Guide. So let's do some samples now:
<cffunction name="GetUsersXML" access="public" returntype="void"> <cfargument name="event" type="any" required="true"> <!--- Get a users query ---> <cfset var qUsers = getUserService().getUsers(); <!--- Render them ---> <cfset event.renderData(type="WDDX",data=qUsers)> </cffunction> <cffunction name="GetUsersJSON" access="public" returntype="void"> <cfargument name="event" type="any" required="true"> <!--- Get a users query ---> <cfset var qUsers = getUserService().getUsers(); <!--- Render them ---> <cfset event.renderData(type="JSON",data=qUsers)> </cffunction> <cffunction name="saveUser" access="public" returntype="void"> <cfargument name="event" type="any" required="true"> <!--- Populate a bean object ---> <cfset var oUser = getPlugin("beanFactory").populateBean('model.user')> <cfset var userSaved = false> <cfif oUser.validate()> <!--- Save it ---> <cfset getUserService().save(oUser)> <cfset userSaved = true> </cfif> <!--- Render save results---> <cfset event.renderData(type="plain",data=userSaved)> </cffunction>
Did you expect more? Nope, that is it. You get the data you want to return and you then use the event.renderData() method. You can do all kinds of combinations and setups, but the basics are there.
The ColdBox Proxy
One of the great tools you will find in the ColdBox Platform is the ColdBox proxy. This proxy element converts this MVC framework into a remote-driven framework. You can use it for integrating Flex/Air/AJAX and Remote calls. In this guide we will only touch AJAX, but the concepts are the same. For an in depth guide, please read the ColdBox Proxy Guide. So let's start with the basics.
What is the proxy
The proxy is just a simple cfc that you will use and interact with from remote systems like AJAX. You call it or use data binding with it or even use the great coldfusion 8 tag: cfajaxproxywith it. It has several utility methods that you can use when dealing with remote calls. Some are shown below, for a full list, please visit the latest API. I would also recommend you check out the sample application called CF8Ajax in the bundle download. It contains all kinds of AJAX-Coldbox goodness!!
Useful Methods (There are more)
| method | brief description |
| process | execute an event remotely. You call this method and pass in an event and any arguments you like. The framework will then simulate an event request and return you data or the entire request collection. This is determined by you by a setting in the configuration file. Your event handlers can now return data instead of setting views to render. The framework morphs into a remote framework. |
| announceInterception | The ability to announce an interception and send in a structure of data. |
| getPlugin | Ability to get a coldbox plugin |
| getBean | Ability to get a bean from an IoC container |
| tracer | Ability to trace messages to the debugger |
| getColdboxOCM | Get a reference to the coldbox cache. |
Techniques
There are two techniques when interfacing with the proxy:
- Calling the process() method or calling a method that uses the process() method to execute an event within coldbox.
- Calling a method in a proxy object that get's data from a service layer directly via the getBean() or getIOCFactory() methods.
Which one you use, well depends on your requirements and interactivity. If you have a service layer that can provide you with data directly with no request flow or security, then use method 2, else maybe method 1 is your cup of tea.
How ?
The greatest question of all. Well, in the distro application template you will find a basic coldboxproxy.cfc that can be used for remote operations. The inherent basics here is that you have a component that extends the base coldbox proxy class: extends=coldbox.system.extras.ColdboxProxy. Below is this simple cfc
<cfcomponent name="coldboxproxy" output="false" extends="coldbox.system.extras.ColdboxProxy"> <!--- You can override this method if you want to intercept before and after. ---> <cffunction name="process" output="false" access="remote" returntype="any" hint="Process a remote call and return data/objects back."> <cfset var results = ""> <!--- Anything before ---> <!--- Call the actual proxy ---> <cfset results = super.process(argumentCollection=arguments)> <!--- Anything after ---> <cfreturn results> </cffunction> </cfcomponent>
You can use this simple proxy to call events via the process method. How? Here is a javascript sample using cfajaxproxy:
<!--- Declare the CF Ajax Proxy HERE ---> <cfajaxproxy cfc="coldboxproxy.cfc" jsclassname="cbProxy"> <script type="text/javascript"> var getArtists = function(){ var cbox = new cbProxy(); // Setting a callback handler for the proxy automatically makes // the proxy's calls asynchronous. cbox.setCallbackHandler(populateArtists); cbox.setErrorHandler(myErrorHandler); // The proxy getArtists function represents the CFC // getArtists function. cbox.process(event:'artists.list'); } </script>
This calls the process method with an argument of event = artists.list. You can extrapolate how to do more stuff from here. So let's do another sample, let's add a method to our proxy so we can do data binding.
<cffunction name="getArtists" output="false" access="remote" returntype="Any" hint="Process a remote call and return data/objects back."> <cfargument name="ARTISTID" type="numeric" required="false" default="0"> <cfset var ReturnValue = "" /> <!--- Its very iteresting.. how I am intracting with service-layer, just bypassing controller layer ---> <cfset ReturnValue = getBean("ArtService").getArtist(argumentCollection=arguments) /> <cfreturn ReturnValue> </cffunction> <cffunction name="getNames" output="false" access="remote" returntype="Any" hint="Process a remote call and return data/objects back."> <cfset var qry = "" /> <!--- CFSELECT (bind ) ---> <cfset var TwoDimensionalArray = ArrayNew(2) /> <!--- Get Qry Directly from ArtService.cfc ---> <cfset qry = getBean("ArtService").getArtist() /> <cfset TwoDimensionalArray[1][1] = '0' /> <cfset TwoDimensionalArray[1][2] = 'Please select' /> <cfloop query="qry"> <cfset TwoDimensionalArray[qry.CurrentRow + 1][1] = trim(qry.ARTISTID)> <cfset TwoDimensionalArray[qry.CurrentRow + 1][2] = trim(qry.FIRSTNAME & chr(32) & qry.LASTNAME)> </cfloop> <!--- Anything after ---> <cfreturn TwoDimensionalArray> </cffunction>
The two methods above go directly to the service layer by using the convenience method of getBean(). Then some js calls using cfajaxproxy:
<script language="javascript"> var getArtistDetails = function(id){ document.getElementById('empData').innerHTML = 'Please wait! loading data...<br><br><img src="css/8-1.gif">'; var e = new cbProxy(); e.setCallbackHandler(populateArtistDetails); e.setErrorHandler(myErrorHandler); // This time, pass the employee name to the getArtists CFC // function. e.getArtists(id); } </script>
The last sample is another method added to our proxy object that get's some content:
<cffunction name="dspTab2" output="false" access="remote" returntype="any" hint="Process a remote call and return data/objects back."> <cfset var results = "" /> <!--- call even handler to get query data etc ---> <cfset arguments["event"] = "ehAjax.dspTab2"> <!--- Call the actual proxy ---> <cfset results = super.process(argumentCollection=arguments)> <cfreturn results> </cffunction>
This simple method executes the process() method on its base class, our coldbox proxy, and then returns the results in whatever format they come in. So our ehAjax.dspTab2 handler can look something like this:
<!--- tab2 content ---> <cffunction name="dspTab2" access="public" returntype="any" output="false"> <cfargument name="Event" type="coldbox.system.beans.requestContext"> <!--- send back to proxy ---> <cfset event.renderData(type="plain",data=renderView('ajax/vwTab2')) /> </cffunction>
How cool is that, we just used the renderData method to render a view remotely. How COOL is that? You can see from this example, that ColdBox truly offers flexibility and great interaction with any remote caller.
Some more samples below:
//CFGRID data binding <cfform> <cfgrid name = "FirstGrid" format="html" font="Tahoma" fontsize="12" pageSize="10" width="100%" preservePageOnSort="yes" bind="cfc:coldboxproxy.getAllArtist({cfgridpage},{cfgridpagesize},{cfgridsortcolumn},{cfgridsortdirection})" > <cfgridcolumn name="ARTISTID" display="true" header="ARTIST ID"/> <cfgridcolumn name="ARTNAME" display="true" header="Name"/> <cfgridcolumn name="FIRSTNAME" display="true" header="First Name"/> <cfgridcolumn name="LASTNAME" display="true" header="Last Name"/> <cfgridcolumn name="EMAIL" display="true" header="Email"/> </cfgrid> </cfform> //AUTO SUGGEST <cfform> <h2>CFINPUT Auto-Suggest:</h2> <p>Type <strong>Ma</strong> or <strong>Ch</strong> </p> <cfinput type="text" name="employeename" autosuggestminlength="2" autosuggest="cfc:coldboxproxy.SearchName({cfautosuggestvalue})"> </cfform> <!--- CF8 cfgrid using ajax cfform is mendatory for using ajax stuff ---> <h1>cfselect bind to remote cfc:</h1> <cfoutput> <cfform name="mycfform"> <!--- The States selector. The bindonload attribute is required to fill the selector. ---> <cfselect name="ArtistID" bind="cfc:coldboxproxyS.getNames()" bindonload="true"> <option name="0">--select--</option> </cfselect> </cfform> </cfoutput>
ColdBox Debugger
As you know, ColdBox provides you (The Developer) with many great tools and visual representations of your application. The ones that are invaluable for AJAX/Remote development are the cache panel monitor and the execution profiler monitor. You can read more about these panels by Clicking Here.
Here is a screenshot of the Cache Monitor:

Here is screenshot of the execution profiler:

What you will find in the execution profiler that is invaluable, is that if you are doing ajax calls via the coldbox proxy, then you can actually see that data that comes in a request, then see the execution of the request, and then finally see the outcome of the request. No need to figure out what in the world happened during that call. The monitor is an essential tool in today's web application development.
