Ask a Jedi: Removing Pagination from CFGRID
Nathan asks:
I am recently getting into CF8 and Ajax features and for doing so building a small application to add items to a cart. I have it setup currently that items are in a select box and a cfgrid shows some item information of the item selected. Since, at a time only one item can be selected, I want to remove the pagination that comes by default with cfgrid. I am able to do that if I get a result query and use the cfgrid with a query attribute, but if I go for a dynamic bind, the pagination controls are present.
This was an interesting problem. First, let's be sure we are clear on what Nathan is seeing. The sexy new CFGRID added in ColdFusion 8 allows you to either directly pass a query to the grid itself (with a query defined on the same page, or loaded via CFC, UDF, etc) or load it via Ajax. This is done with the bind attribute.
If you pass the query to the grid then the pagination controls are not displayed. For example:

Even if you set a pagesize attribute, it will be ignored and the entire query will be displayed in the grid. Now compare this a grid that loads it's data via the bind attribute:

So how do you get rid of the bar? I knew that ColdFusion provided a function, ColdFusion.Grid.getGridObject, that would give me direct access to the grid. I figured then it would be a simple matter of checking the Ext API docs to see if there was a method to hide the panel.
I dug... and I dug... but I was unable to find anything that made sense to me. Using Firebug and the console.dir command (think of it as a ColdFusion dump), I finally found this:
var myGrid = ColdFusion.Grid.getGridObject('entries');
myGrid.view.getFooterPanel().setVisible(false);
myGrid.view.refresh();
This seemed to work well. I then added an ajaxOnLoad() call to run the code on load. Here is the complete example:
<html>
<head>
<script>
function testit() {
var myGrid = ColdFusion.Grid.getGridObject('entries');
myGrid.view.getFooterPanel().setVisible(false);
myGrid.view.refresh();
}
</script>
</head>
<body>
<cfform name="test">
<cfgrid autowidth="true" name="entries" format="html" width="600" bind="url: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>
</cfform>
<cfset ajaxOnLoad("testit")>
</body>
</html>
I'm not sure this is the best way to do it (I've actually got an Ext book on the way to me for review purposes), but it seems to work ok. Another solution would have been to use the drop down to drive a bound cfdiv tag. That cfdiv then could have loaded both an inline query and cfgrid.
Comments
On the topic of the ExtJS libraries, is the whole lib included by Adobe or are only certain aspects of it (like the grid libraries implemented)?
Ray, since Ext has changed their licensing model and moved to 2, do you know if Adobe is going to be including Ext 2 in a future update?
Tony
<cfoutput>#serializeJSON(QueryConvertForGrid(query, page, pagesize))#</cfoutput>
It works like a charm.
Here is how I've implemented it, adding a button to add a record with only a large red "+" icon in the middle of the button, and a delete button with an icon and the words "Delete Selected".
function initGrid() {
grid = ColdFusion.Grid.getGridObject("RecipeHerbGrid");
var gridFoot = grid.getView().getFooterPanel(true);
var bbar = new Ext.Toolbar(gridFoot);
bbar.addButton({
cls:"x-btn-text-icon",
icon:"icons/add.png",
handler:onAdd
});
bbar.addSeparator();
bbar.addButton({
text:"Delete Selected",
cls:"x-btn-text-icon",
icon:"icons/delete.png",
handler:onDelete
});
}
Heck, while i'm posting this, I should also just go ahead and post the handler functions, in case it helps anyone. Took me a long time to pull all this together:
function onAdd(button,event){
ColdFusion.Window.show('addRecipeHerbWindow');
// console.log(button);
// console.log(event);
}
function addRecipeHerb() {
//send data to CFC to add RecipeHerb, the result will be handled by handleResult function above
var f = document.frmRecipeHerb;
dataproxy.addNewRecipeHerb (
f.recipeVariationId.value,
f.herbId.value,
f.weight.value
);
ColdFusion.Window.hide('addRecipeHerbWindow');
ColdFusion.Grid.refresh('RecipeHerbGrid', true);
}
function onDelete(){
ColdFusion.Window.show('deleteRecipeHerbWin');
}
function deleteRecipeHerb(confirmMessage) {
// if user choose to delete, then send the CFC call, otherwise just sit back!
if (confirmMessage == 'yes')
{
var grid = ColdFusion.Grid.getGridObject("RecipeHerbGrid");
var record = grid.getSelections();
// remember, CF makes column names to all UPPERCASE, so dont forget to do that
dataproxy.deleteRecipeHerb(record[0].data.RECIPEHERBID);
}
ColdFusion.Window.hide('deleteRecipeHerbWin');
ColdFusion.Grid.refresh('RecipeHerbGrid', true);
}
function editRecipeHerb() {
var grid = ColdFusion.Grid.getGridObject("RecipeHerbGrid");
var record = grid.getSelections();
dataproxy.editRecipeHerb (
record[0].data.RECIPEHERBID,
record[0].data.THEWEIGHT,
record[0].data.PINYIN
);
ColdFusion.Grid.refresh('RecipeHerbGrid', true);
}
It's all wired to the back end using the cfajaxproxy tag.
Can you publish code for the getentries.cfm?
<cfquery name="entries" datasource="blogdev">
select *
from tblblogentries
<cfif len(url.sort) and len(url.dir)>
order by #url.sort# #url.dir#
</cfif>
</cfquery>
<cfset data = queryConvertForGrid(entries, url.page, url.pagesize)>
<cfset encoded = serializeJSON(data)>
<cfcontent type="text/json" reset="true"><cfoutput>#encoded#</cfoutput>
I am receiving fallowing error:
window:global: 'e' is undefined (http://localhost/CFGrid_Test/test.cfm?cfdebug=true..., line 525)
This is a code for Test.cfm
<html>
<head>
<script>
function testit()
{
var myGrid = ColdFusion.Grid.getGridObject('entries');
myGrid.view.getFooterPanel().setVisible(false);
myGrid.view.refresh();
}
</script>
</head>
<body>
<cfform name="test">
<cfgrid autowidth="true"
name="entries"
format="html"
width="600"
bind="url:getentries.cfm?page={cfgridpage}&pagesize={cfgridpagesize}&sort={cfgridsortcolumn}&dir={cfgridsortdirection}">
<cfgridcolumn name="id" header="ID">
<cfgridcolumn name="price" header="Price">
<cfgridcolumn name="product" header="Product">
</cfgrid>
</cfform>
<cfset ajaxOnLoad("testit")>
</body>
</html>
This is a code for getentries.cfm
<cfset data = queryNew("id,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, "ID", x)>
<cfset querySetCell(data, "price", total+0, x)>
<cfset querySetCell(data, "product", product, x)>
</cfloop>
<cfset data = queryConvertForGrid(getArtists, url.page, url.pagesize)>
<cfset encoded = serializeJSON(data)>
<cfcontent type="text/json" reset="true"><cfoutput>#encoded#</cfoutput>
Gecko (and similar) browsers pass a reference to an event object as the first parameter when calling a function assigned to an intrinsic event handler this way. IE doesn't, it uses a global 'event' variable.
Local variable "event" here masks IE's global event variable. As soon as I Modified function as fallowing
function testit()
{
var e = e || window.event;
var myGrid = ColdFusion.Grid.getGridObject('entries');
myGrid.view.getFooterPanel().setVisible(false);
myGrid.view.refresh();
}
everything starts working.
I do have another question s about CFGRID
How I can change background color of the one sell (let say cell in column 3) depending of cell value in column 2
Thanks in advance.
One more question. Is it possible to populate CFGRID through cfajaxproxy call?
If you be able to find blog URL I will be very much appreciated.
Did you sow my question about changing background color on the grid cell depending of value in another grid cell?

I am surprised that Adobe did not include some of these simpler options in their CF tags for use and that we have to dig into ExtJS to use them. There is an additional issue here that the grid look will change after the page has loaded (correct me here if I am wrong).
The advantage of using cfgrid with bind instead of using a cfdiv with an inline query and cfgrid is that cfdiv always shows the "loading graphic" whenever the select box is changed, while cfgrid with bind is much more dynamic. But the cfdiv solution sounds more pleasing to me right now than modifying the grid after it has loaded.