Coldfusion 8's CFGRID

One of the tags to receive an upgrade in CF8 is the CFGRID tag. I can honestly say that I have never had a need to use this tag in the past although for some I can see that it 'could' have been useful.

The added support comes in the form of: type="html",bind,bindOnLoad,pageSize,prefesrbPageOnSort,stripeRows,stripeRowColor.

Lets focus for a minute on the new bind attribute. This attribute allows you to specify an expression to fill the grids contents. This expression can come in three flavors: You can bind directly to a CFC, a javascript function, or additionaly a URL.

The old restriction on the cfgrid is still in place, that being that it has to live within the bounds of a CFFORM tag, that's a small price to pay for ajax functionality right?

So here is a code snippet of the cfgrid in action:


<cfform name="tableform">
    <cfgrid format="html" name="grid_Tables" pagesize="7" selectmode="row"
bind="cfc:components.artgallery.artist.getArtists({cfgridpage},{cfgridpagesize},{cfgridsortcolumn},{cfgridsortdirection})">

                        <cfgridcolumn name="ARTISTID" display="No"/>
                        <cfgridcolumn name="FIRSTNAME" header="FIRSTNAME" >
                        <cfgridcolumn name="LASTNAME" header="LASTNAME" >
                        <cfgridcolumn name="CITY" header="CITY" >
                        <cfgridcolumn name="STATE" header="STATE" >
    </cfgrid>
</cfform>
</cfoutput>

Nothing too fancy other than the bind right? lets look at that a little closer.

bind="cfc:components.artgallery.artist.getArtists({cfgridpage},{cfgridpagesize},{cfgridsortcolumn},{cfgridsortdirection})"
In the bind expression we specify that we are going to be calling a CFC directly, followed by the dot notation down to the component and finishing off with the method (getArtists). Following the method call are the arguments, the grid requires all of the arguments you see here, and the curly braces indicate that they are bound to the grid itself. This way when someone clicks on a row header it will automatically refresh the grid by calling the CFC again with the gridsortcolumn and gridsortdirection arguments, nifty huh?

Here is what it looks like using the default styling:

You should immediately notice the bar at the bottom. This additional little functionality provides automatic paging of your data and you set that by specifiying the pageSize attribute. This value is automatically passed onto your cfc as well.

Lets take a quick look at the code for the Artist cfc:

    <cffunction name="getArtists" access="remote">
        <cfargument name="page" required="yes">
        <cfargument name="pageSize" required="yes">
        <cfargument name="gridsortcolumn" required="yes">
        <cfargument name="gridsortdirection" required="yes">

    <cfquery name="members" datasource="cfartgallery">
        SELECT ARTISTID, FIRSTNAME, LASTNAME, CITY, STATE
        FROM ARTISTS
        <cfif gridsortcolumn neq ''>
        order by #gridsortcolumn# #gridsortdirection#
        </cfif>
    </cfquery>
    <cfreturn queryconvertforgrid(members,page,pagesize)/>
    </cffunction>

Nothing new here, or is there? Well if you spotted the queryconvertforgrid function as new you are right, its nothing I built, its a new function desiged specifically for converting a query into something that the cfgrid can use, it also takes the page, and pagesize attributes as arguments so it only passes back the specific page needed.

Another thing, if you have firebug installed you will be able to see how the call is made to your cfc. For my example I left out the argument collection: http://localhost/mycf/components/artgallery/artist.cfc?method=getArtists&returnFormat=json&argumentCollection=

for binding to CFC's coldfusion automatically appends the argument pair "returnFormat=json" this ensures that what you get back is a valid json dataset.

There is a lot more you can do with the cfgrid and a bit of javascript coding, you could use the and tags which allow you to interact with your grid by attaching events handlers to specific events in the grid and then performing actions.

You could quite easily set up master/deatail pages using ajax calls to get the data and update a detail form on the same page. And then update the data asynchronously and then at the same time automatically refresh the grid, pretty darn cool!

In future posts I will explore setting up a master detail form and creating editable grids, and exploring some of the other new features of Coldfusion 8

Related Blog Entries

27 Comments to "Coldfusion 8's CFGRID"- Add Yours
Gary's Gravatar Fixed a typo in the gridsortdirection argument, would generate an error when
you clicked on one of the column headers.
# Posted By Gary | 6/20/07 12:12 PM
abul's Gravatar Is it possible to add image in a cfgrid in Ajax.
# Posted By abul | 8/1/07 5:14 PM
Gary Gilbert's Gravatar Abul,

Sorry at the moment it is not possible to create custom renderers for cfgrid. It may be possible if you manipulate the base ext.grid objects column model after Coldfusion writes the code.

Your best choice is to use the ext grid. I have a tutorial on ext grid with custom renderer: http://www.garyrgilbert.com/blog/index.cfm/2007/7/...
# Posted By Gary Gilbert | 8/1/07 5:42 PM
Hal Helms's Gravatar Actually, you can have images in a cfgrid, as well as other HTML, but you'll have to add this to your query itself. Cfgrid will render any HTML (including calls to images) found there. Ray Camden blogged about this recently.
# Posted By Hal Helms | 8/15/07 6:47 PM
Gary Gilbert's Gravatar @Hal,

Thanks for the info Hal. I didn't think to add the img tag directly in the query. I guess as you say you can display just about anything in the grid. I was more thinking in the lines of having a cell renderer not formulating html on the server-side and sending it to the front end.
# Posted By Gary Gilbert | 8/16/07 1:00 PM
Kebab Dylan's Gravatar ok, so I am trying to get this to work and i am getting a "error:http: Error invoking CFC /club.cfc : Not Found"

if i call the method directory from the cfml file, no problem, but once I try to use binding, it cannot find the cfc.

any ideas?
# Posted By Kebab Dylan | 10/10/07 10:06 PM
Gary Gilbert's Gravatar @kebab,

can you get to your cfc using a url? for example I have a cfc in webroot\dev\com\gg called fileExplorer.cfc and to access the getDirectories method in the cfc I can use the URL below

http://www.garyrgilbert.com/dev/com/gg/fileexplore...=

which returns a result to me in a json array.

The bind attribute would therefore look like "cfc:dev.com.gg.fileExplorer.getDirectories({cftreeitempath},{cftreeitemvalue})"

As a side note you can NOT use a cf mapping your cfc MUST be web accessible!
# Posted By Gary Gilbert | 10/10/07 1:34 AM
Ryan's Gravatar I have it all setup, but the problem I am running into is that there is an error stating it cannot execute the query, even though I put the query on another page, and dump it out, it shows up fine.
# Posted By Ryan | 10/19/07 5:26 PM
Kebab Dylan's Gravatar yes. it is accessible and i can call the get method and get back text...
# Posted By Kebab Dylan | 11/2/07 10:55 PM
Tre's Gravatar In past versions of the grid there was not a way to select multiple rows, how about this version?
# Posted By Tre | 11/14/07 8:52 PM
Felipe's Gravatar Hi there guys, one question.. I need to have a dropdown "cfselect" that will trigger some code to refresh the html grid with different queries... I have all figured it out except the function to call the cfgrid from the cfselect onchange using the new html type in cf8.

Any help?

Thanks in advance.
# Posted By Felipe | 11/20/07 10:37 AM
Gary Gilbert's Gravatar If I understand correctly you want the cfgrid to refresh with new information when you select something in the cfselect right?

In order to do that you would bind the grid to the onchange event of the cfselect. To do that you would change the bind expression on your grid.
<cfselect name="myselect" bind="cfc:mycfc.getSelectData()" bindonload="true">
<cfgrid ..... bind="cfc:mycfc.getGridData({cfgridpage},{cfgridpagesize},{cfgridsortcolumn},{cfgridsortdirection},{myselect})"

This will automatically tie your grid to the value field of your select.
# Posted By Gary Gilbert | 11/20/07 1:38 PM
Gary Gilbert's Gravatar I wrote a blog entry on how to bind a grid to a select box

http://www.garyrgilbert.com/blog/index.cfm/2007/11...
# Posted By Gary Gilbert | 11/21/07 6:49 PM
Matt's Gravatar I set a demo using cflayout / cflayouarea / cfform / cfgrid. I thought it would be nice to have a search feature as well so I added an input that look like it's part of the ajax control at the bottom of the grid. I have the input set onChange so the grid filters as you type.

The problem is now that the cfform has a input the enter key submits the form instead of using the ajax controls and totally throws the page off. I'm having a really hard time finding a working solution of a cfgrid with a search in the same ajax control.

Any suggestions?
# Posted By Matt | 9/21/09 2:10 AM
Colin's Gravatar I am trying to add additional arguments (search critiera) to my cfgrid bind and keep.
and keep getting this error using cfdebug :
"global: 'Dav' is undefined "
"Dav' is the value of the search field (arguments.lmlname)
I would really appreciate the help as I've been at this for several hours
and cannot pass the search criteria from search form using cfgrid bind
# Posted By Colin | 11/7/09 12:53 AM
Gary's Gravatar @colin,

It would be great to see the code you are trying, want to send it to me?
# Posted By Gary | 11/8/09 6:34 PM
John Jarrard's Gravatar I'm having an issue where a column is sorting AlphaNumeric even though all the data is numeric. Here's what a typical sort is looking like:

998
996
9
887
886
8
737
747
727
718
6

Is there any way to tell a column to sort using numeric data rather than alpha numeric? Every record has a number in that column, so it shouldn't be an issue...

JJ
# Posted By John Jarrard | 5/13/10 4:51 PM
KJ's Gravatar I have a cfgrid that has a editable column and once a user edits the column
it updates the database and another column shows a different value.
Everything updates ok except to see the new value in the other column
the grid has to be refreshed and I'm now sure how to refresh the grid
after an update.

<cfgrid format="html" name="Pricestandardreview" pagesize="10" bindonload="true" sort="true"
bind = "cfc:test.getSTDReview({cfgridPage},{cfgridpagesize},{cfgridsortcolumn},{cfgridsortdirection})" selectmode="edit"
onchange= "cfc:test.editSTDReview({cfGridAction},{cfgridrow},{cfgridchanged})" >
<cfgridcolumn name="full_account" display=true header="Customer Number"/>
<cfgridcolumn name="DBID" header="DBID" select="no" display=no />
<cfgridcolumn name="SCENARIO_SEQ" header="SCENARIO_SEQ" select="no" display=no />
<cfgridcolumn name="ACCOUNT_NUM" header="ACCOUNT_NUM" select="no" display=no />
<cfgridcolumn name="SCENARIO_DET_SEQ" header="SCENARIO_DET_SEQ" select="no" display=no />
<cfgridcolumn name="account_name" display=true header="Customer Name" select="no"/>
<cfgridcolumn name="tank_num" display=true header="Tank Number" select="no"/>
<cfgridcolumn name="product" display=true header="Product Code" select="no"/>
<cfgridcolumn name="department_code" display=true header="Department code" select="no"/>
<cfgridcolumn name="tank_acquired" display=true header="Tank Acquisition Date" mask="mm/dd/yyyy" select="no"/>
<cfgridcolumn name="zone" display=true header="Zone" select="no"/>
<cfgridcolumn name="tank_size" display=true header="Tank Size" select="no"/>
<cfgridcolumn name="tank_rental_amount" display=true header="Tank Rental Amount" select="no"/>
<cfgridcolumn name="tank_rental_period" display=true header="Total Rental Period" select="no"/>
<cfgridcolumn name="tank_rental_status" display=true header="Tank Rental Status" select="no"/>
<cfgridcolumn name="curr_price_sub_level" display=true header="Price Sublevel" select="no"/>
<cfgridcolumn name="minimum_bill_table" display=true header="Minimum Bill Code" select="no"/>
<cfgridcolumn name="curr_base_price_code" display=true header="Base Price Code" select="no"/>
<cfgridcolumn name="curr_deviation" display=true header="Deviation" select="no"/>
<cfgridcolumn name="gross_amount" display=true header="Gross Amount" select="no"/>
<cfgridcolumn name="r12_gallons" display=true header="Gallons" select="no"/>
<cfgridcolumn name="new_base_price_code" display=true header="New Bpc" select="yes" />
<cfgridcolumn name="new_deviation" display=true header="New Deviation" select="yes" />
<cfgridcolumn name="new_price_per_gallon" display=true header="New Price" select="no" />
<cfgridcolumn name="PRICE_VARIANCE" display=true header="Price Variance" select="no" />
<cfgridcolumn name="TOTAL_VARIANCE" display=true header="Total Variance" select="no" />
</cfgrid>
# Posted By KJ | 6/1/10 4:40 PM
sainisha's Gravatar iam trying to use cfgrid with bind and all i get back is grid with no data in it. i have tried the basic simple example and it doesnt work. however it works great with the query but not when i use the bind attribute. please help. i need to be able to complete my task quickly and this has been dragging me down.
# Posted By sainisha | 6/23/10 9:47 PM
gary's Gravatar Have you used firebug to see what message is being returned? Remember this is an ajax call so you have to use firebug to see what CF returns.

You probably have some small simple syntax error or something.
# Posted By gary | 6/23/10 8:53 AM
sainisha's Gravatar thanks Gary for answering back. i have tried the same code you used in the example but changed the datasource so that it can accept my database.the error it shows in firebug is
grid.extproxy.loadresponse.totalrowcountmissing
but i havent used totalrowcount anywhere.

im posting my code here employee.cfm
<cfform name="tableform">
<cfgrid format="html" name="grid01" pagesize=5 sort=true
bind="cfcl:employeefunction.cfm?page={cfgridpage}&pageSize={cfgridpagesize}
&sortCol={cfgridsortcolumn}&sortDir={cfgridsortdirection}">

<cfgridcolumn name="employee_master_id" display="No"/>
<cfgridcolumn name="first_name" header="FIRSTNAME" >
<cfgridcolumn name="last_name" header="LASTNAME" >
<cfgridcolumn name="division" header="division" >
<cfgridcolumn name="bureau" header="bureau" >
</cfgrid>
</cfform>

employeefunction.cfc
<cffunction name="getemployees" access="remote">
<cfargument name="page" required="yes">
<cfargument name="pageSize" required="yes">
<cfargument name="gridsortcolumn" required="yes">
<cfargument name="gridsortdirection" required="yes">

<cfquery name="members" datasource="#request.dsn#">
SELECT employee_master_id,first_name,last_name,division,bureau
FROM employee_master
<cfif gridsortcolumn neq ''>
order by #gridsortcolumn# #gridsortdirection#
</cfif>
</cfquery>
<cfreturn queryconvertforgrid(members,page,pagesize)/>
</cffunction>
# Posted By sainisha | 6/24/10 4:41 PM
Gary Gilbert's Gravatar run a simple test and see what the json looks like that is returned from your function getemployees without trying to plug it into the grid.

<cfset obj = createobject("component","employeefunction")>
<cfdump var="#getemployees(1,20,'','')#">

the json should have an entry called "totalrowcount" if it doesnt then there is a bug in CF
# Posted By Gary Gilbert | 6/24/10 4:51 PM
sainisha's Gravatar It returns the rowcount as 654 which is correct. it is dumping the query out fine.
# Posted By sainisha | 6/24/10 5:50 PM
sainisha's Gravatar Gary,
i just applied the cf9 cumulative fix also to see if that will rectify the problem with cfgrid but none.please suggest me what else can be done. the issue is i would like to use cfgrid with bind so that i can make use of the pagination but this doesnt simply seem to work. i cant understand what else needs to be done. i did create the virtual directory for cfide too which i found as one of the solutions but that didnt work either. im running out of time and options too.please help
# Posted By sainisha | 6/24/10 8:58 PM
Gary Gilbert's Gravatar Honestly Im not sure what the problem is, I will have to dig into this a bit more. According to the error message the grid is expecting the totalrowcount but is not getting it. Let me whip up an example and see if I can reproduce the error.
# Posted By Gary Gilbert | 6/25/10 9:28 AM
Gary Gilbert's Gravatar @sainisha,

I was so concentrating on the cfc I didnt look at your bind statement!

<cfgrid format="html" name="grid01" pagesize=5 sort=true
bind="cfcl:employeefunction.cfm?page={cfgridpage}&pageSize={cfgridpagesize}
&sortCol={cfgridsortcolumn}&sortDir={cfgridsortdirection}">

your bind statement is completely wrong!

firstly when you are binding a cfc you should have cfc and not "cfcl" secondly when binding a cfc you need to use the dot notation to where the cfc is, if its in the same directory as the grid cfml page then that is find, thirdly when binding a cfc you dont' put a file ending and certainly not cfm when its a cfc.

Look at this bind statement and compare that to yours

<cfgrid format="html" name="grid_Tables" pagesize="7" selectmode="row"
bind="cfc:components.artgallery.artist.getArtists({cfgridpage},{cfgridpagesize},{cfgridsortcolumn},{cfgridsortdirection})">

quite a huge difference... perhaps you should fix your bind statement and try again.
# Posted By Gary Gilbert | 6/25/10 9:33 AM
sainisha's Gravatar Hi Gary,
sorry for the syntax error. i rectified the cfc syntax and tried it . still the same problem. actually i was also trying the url bind option and in trying to copy the code i must have copied the other one. i tried the sample code at home system and it works great. inside my application i have this problem. looks like something on the application side is suppressing it.
# Posted By sainisha | 6/25/10 4:22 PM

Powered By Railo

Subscribe

Subscribe via RSS
Follow garyrgilbert on Twitter Follow me on Twitter
Or, Receive daily updates via email.

Tags

adobe air ajax apple cf community cfml coldfusion examples ext flash flex google javascript max2007 max2008 misc open source programming railo software technology ui

Recent Entries

Converting structkeys to lowercase

Blogroll

An Architect's View
CFSilence
Rey Bango
TalkingTree

Wish List

My Amazon.com Wish List