Custom grid renderers with CFGRID

I’ve been playing a bit with CFGRID lately (as have others) and I found that by taking a look at Ext’s documentation, there are some very powerful features hiding within the CFGRID tag. ColdFusion provides a function, ColdFusion.Grid.getGridObject, that when used gives you a handler to the underling Ext Grid object. By looking at the documentation, you can see which methods are available with the grid. One in particular I thought was pretty neat was the ability to add custom column renderers. What is that?

Well imagine you have data being fed into the grid that you do not have control over. For example – perhaps you have price information that isn’t formatted nicely. Turns out Ext has a set of built in formatters that you can apply to grid columns, one of them being a money formatter. What if you have some other logic? Maybe you want to flag a price that is lower than 10 dollars? Again, using the Ext API, you can write your own formatter just for this purpose.

I’ve only just begun to scratch the surface of Ext, but here is a quick and dirty example to give you an idea of what is possible.

First lets create a simple grid:


<cfset data = queryNew("price,product")>
<cfloop from=1 to=10 index="x">
<cfset total = randRange(20,100) & "." & randRange(1,99)>
<cfset product = "Product #X#">
<cfset queryAddRow(data)>
<cfset querySetCell(data, "price", total+0, x)>
<cfset querySetCell(data, "product", product, x)>
</cfloop>

<cfform name="test">
<cfgrid autowidth="true" name="data" format="html" query="data" width="600">
<cfgridcolumn name="price" header="Price">
<cfgridcolumn name="product" header="Product">
</cfgrid>
</cfform>

I’m using a hard coded query with products and prices. This is then fed directly into the grid. Note that I’m not using Ajax here.

Now let’s look at how we can add a custom column renderer. The first thing we need to do is to set up the page to call a function when the grid is done loading. We do this with ajaxOnLoad:


<cfset ajaxOnLoad("testgrid")>

Because I’m not “properly” using Ajax on my page, I also added an import:


<cfajaximport/>

I’ve mentioned this hack before, and credit goes to Todd Sharp for discovering. Now let’s look at the JavaScript:


myf = function(data,cellmd,record,row,col,store) {
if(data == "Product 4") return "<b>" + data + "</b>";
else return data;
}
testgrid = function() {
mygrid = ColdFusion.Grid.getGridObject('data');
cm = mygrid.getColumnModel();
cm.setRenderer(0, Ext.util.Format.usMoney);
cm.setRenderer(1,myf);
mygrid.reconfigure(mygrid.getDataSource(),cm);
}

Skip the first function and focus in on testgrid. Testgrid is a horrible name but I was just playing around with the code so forgive me. I grab the grid using the ColdFusion.Grid.getGridObject API mentioned before. Everything after this is based on my reading of the Ext docs. I grab the columns using the getColumnModel function. I apply a renderer to columns 0 and 1 (you will never convince me that 0 based indexes make sense). The first renderer is a built one named usMoney. The second one is a custom function named “myf”. usMoney will do what you imagine – format money. The second was hard coded to look for Product 4, and when found, bold it. I then use reconfigure to apply the column model back to my grid.

You can see an example of this here. Full source code is below.


<cfajaximport/>
<html>

<head>
<script>

myf = function(data,cellmd,record,row,col,store) {
if(data == "Product 4") return "<b>" + data + "</b>";
else return data;
}
testgrid = function() {
mygrid = ColdFusion.Grid.getGridObject('data');
cm = mygrid.getColumnModel();
cm.setRenderer(0, Ext.util.Format.usMoney);
cm.setRenderer(1,myf);
mygrid.reconfigure(mygrid.getDataSource(),cm);
}
</script>
</head>

<body>

<cfset data = queryNew("price,product")>
<cfloop from=1 to=10 index="x">
<cfset total = randRange(20,100) & "." & randRange(1,99)>
<cfset product = "Product #X#">
<cfset queryAddRow(data)>
<cfset querySetCell(data, "price", total+0, x)>
<cfset querySetCell(data, "product", product, x)>
</cfloop>

<cfform name="test">
<cfgrid autowidth="true" name="data" format="html" query="data" width="600">
<cfgridcolumn name="price" header="Price">
<cfgridcolumn name="product" header="Product">
</cfgrid>
</cfform>

<cfset ajaxOnLoad("testgrid")>
</body>
</html>