On another listserv (sorry, can't say where, would have to kill you), a user brought up an interesting problem. He was using CFGRID (the Ajax variety) and had bound it to a CFC. No big deal, right? Well his API was somewhat complex. How complex? His method took 61 different arguments. Now frankly I think that is a bit too much (like Paris Hilton doing political ads too much), but it's what he needs and he wants it to work. The problem he is running into though is the size of the URL. You can probably imagine that a URL with 61 different arguments is going to get a bit long, and at some point, it stops working. The solution is simple. Switch to POST. But how do we do that with cfgrid?

Unfortunately there is no simple "usePost" attribute you can add to cfgrid. But do not forget that bindings in ColdFusion 8 can use 3 forms: CFC, URL, and JavaScript. The grid can work with any of these forms as long as you return the right type of object. If you want to use JavaScript, it's actually very well documented in the CF Developer's Guide:

If you manually create a JavaScript object or its JSON representation, it must have two top-level keys:

  • TOTALROWCOUNT: The total number of rows in the query data set being returned. This value is the total number of rows of data in all pages in the grid, and not the number of rows in the current page.
  • QUERY: The contents of the query being returned. The QUERY value must also be an object with two keys:
  • COLUMNS: An array of the column names.
  • DATA: A two-dimensional array, where the first dimension corresponds to the rows and the second dimension corresponds to the field values, in the same order as the COLUMNS array.

So you could, if you wanted to, manually create the data in JavaScript and return it in your bind function. We don't have to do that though. ColdFusion already provides a way for me to hook up JavaScript to a CFC: cfajaxproxy. So let's break this down and see how it works. First, here is my initial grid. I'm using a URL, not a CFC, and I obviously don't have 61 arguments, but it gives us a base to start with:

<cfform name="test"> <cfgrid autowidth="true" name="entries" format="html" width="600" bind="url:presentations/cfajaxjune5/getentries.cfm?page={cfgridpage}&pagesize={cfgridpagesize}&sort={cfgridsortcolumn}&dir={cfgridsortdirection}"> <cfgridcolumn name="id" display="false"> <cfgridcolumn name="body" display="false">

<cfgridcolumn name="title" header="Title"> <cfgridcolumn name="posted" header="Posted"> </cfgrid>

The first thing I'm going to do is switch to JavaScript for the bind:

<cfgrid autowidth="true" name="entries" format="html" width="600" bind="javascript:getData({cfgridpage},{cfgridpagesize},{cfgridsortcolumn},{cfgridsortdirection})">

I'll then write a basic function:

function getData(page,pagesize,sort,sortdir) { }

At this point, I need to talk to my CFC. I had a URL before, but I quickly changed it to a basic CFC. Note readers - this CFC is incomplete. It ignores the sort. It's just enough to give you the idea:

<cfcomponent>

<cffunction name="getData" access="remote" returnType="any" output="false"> <cfargument name="page"> <cfargument name="pagesize"> <cfargument name="sort"> <cfargument name="sortdir">

<cfset var entries = ""> <cfset var data = "">

<cfquery name="entries" datasource="blogdev"> select * from tblblogentries </cfquery>

<cfset data = queryConvertForGrid(entries, arguments.page, arguments.pagesize)> <cfreturn data> </cffunction>

</cfcomponent>

Now that I have the CFC, let's make a proxy back to it:

<cfajaxproxy cfc="getdata" jsclassname="dataproxy">

Wow, that was pretty hard. I better take a good 2 hour lunch to make up for all the time it took me to hook up client side code and server side code. Why can't ColdFusion make this even easier? I mean it must have taken me 10 seconds to type all this out? Ok, sarcasm aside, we aren't quite done yet. We need to make an instance of the proxy, and most importantly, we need to ensure it uses POST, not GET:

myproxy = new dataproxy(); myproxy.setHTTPMethod("POST");

Now that we have the proxy, let's use it in our function:

function getData(page,pagesize,sort,sortdir) { result = myproxy.getData(page,pagesize,sort,sortdir); return result; }

I don't need that result value, I could just do it in one line, but I like to be verbose.

So let's go over what we did here. We told the grid to bind to a JavaScript function. Whenever a sort is called (by the user clicking on a column) or a page is changed, the javaScript function getData will be called. This function is passed the current state information (page, page size, sort, sortdir). This function uses a proxy (a connection to my CFC) and calls the method. I told it earlier to use POST, so if I did have 61 arguments, it will work just fine. It then returns the data to the grid for display.

Make sense? Here is the entire client side code I used for testing.

<cfajaxproxy cfc="getdata" jsclassname="dataproxy">

<script> myproxy = new dataproxy(); myproxy.setHTTPMethod("POST");

function getData(page,pagesize,sort,sortdir) { result = myproxy.getData(page,pagesize,sort,sortdir); return result; } </script>

<cfform name="test"> <cfgrid autowidth="true" name="entries" format="html" width="600" bind="javascript:getData({cfgridpage},{cfgridpagesize},{cfgridsortcolumn},{cfgridsortdirection})"> <cfgridcolumn name="id" display="false"> <cfgridcolumn name="body" display="false">

<cfgridcolumn name="title" header="Title"> <cfgridcolumn name="posted" header="Posted"> </cfgrid> </cfform>