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>
Archived Comments
@Ray
I know that this question was probably not the point of your example and that you were trying to do this in a simple fashion so that everyone would understand - so please excuse me - but it is an important question to me. If you had set a callback handler then the result returned from the cfc would've actually been sent to the callback function right - and not sent back to getData()? I only point this out because I've really been making an effort of late to set error and callback handlers on all things proxy and to never write a query without a cfqueryparam ever again. All that being said, I've had really odd things happen when I call a js function from a form button and I need to perform custom error checking and other stuff before the submit gets called. This usually happens when I chain function calls meant to perform a series of validation checks and or database lookups before I actually call ColdFusion.Ajax.submitForm.
Thanks in advance for any insight.
Yes. The way my code is written now it is synchronous. I believe it HAS to be, since the grid demands an immediate respond to the bind.
Ray:
Thanks for the nice cfajaxproxy example.
I realize your example has been on the web for quite a while but ...
The way you used two lines in your javascript function with a separate 'return result; line got me thinking.
Would the javascript function be able to access the query result and say, massage some of the column data before passing along to the grid?
Thanks,
Steve
I believe so, yes.
This saved our project. We had been running into memory issues with the CFGrid(html format) and errors with the URI being too large. This method appears to decrease the amount of memory issues and allowed us to change to post. I had two open Cases with Adobe on this. They still need to fix the bind to a cfc memory issue, but helps us out.
Hello Raymond,
I recently upgraded from CF8 to CF10 and having problems with the cfgrid to load. The grid actually loads but the refresh keeps spinning and no data comes. There is a cfc: bind and I can see that the ajax call returns back data but the data is not being displayed in the grid somehow. This was perfectly working in CF8.
Here is the code:
the cfc:
[EDITED]
the ajax returns data like this:
c64 a7a {"QUERY" [EDITED]
'the only difference I see is : "c64 a7a" in teh beginning CF8 was not returning those but can not figure out where they are coming from...
any ideas?
Thank you much!
@Erol: In the future, please do not post code to the blog. I edited your comment to strip out most of the code.
It looks like your server has "Secure JSON Prefix" enabled. Can you check that in the CF Admin?
Raymond,
Thank you so much for your reply. Sure and I apologize that I did no see your warning before posting.
I checked under settings and "Prefix serialized JSON with \\" was not checked. I added <cfset this.secureJSON = "false"> to my application.cfc but I still have the same problem after restarting the application with that setting.
Hmm, not sure then. Is it online where I can see?
Unfortunaltely, it is secure and firewalled. I will keep looking into it, I last tried this:
http://blogs.coldfusion.com...
and added -Djson.numberasdouble=true. to jvm.config but that did not do the trick. If I get the data directly through a query with no binding and ajax then the grid works.
I will post if I figure it out.
Thank you much Raymond!