I was working on a project yesterday, and I was using an editable CFGrid to manage a list of data. On my form I wanted to create a button with an onClick event that would take the data from the selected row in my CFGrid , and then do some processing and update that row on the CFGrid and in the database automatically. To do this I needed some way to update the data in a specific cell on the grid,

but there was no obvious way to do that.

I consulted the Adobe docs and they provide us with a few different grid related functions. Originally I had thought about just writing a function that updates the data through a cfc call then calls ColdFusion.Grid.refresh, which Manually refreshes a displayed grid. I couldn't use this however because when you call it the whole grid page gets refreshed and you loose the row you have selected.

I determined at this point I was going to have to use ColdFusion.Grid.getGridObject, which Gets the underlying Ext JS - JavaScript Library object for the specified HTML format CFGrid control. Then I began a long and tedious process of trying to figure out how to use yet another giant JavaScript Library that I am completely unfamiliar with. The ext documentation was a little bit of a help, but ultimately it came down to me just fiddling with it for several hours until it clicked in my head.

Here is a working sample of what I am talking about. This is a simplified version of what I had to do for my real project but it will give you the important part. This is a little contacts manager, and if you select a row and click the "Toggle Cool Factor" button then the selected rows "cool" flag will be changed.

Now for the example code. This code is pretty much like all the other blog entries you see out there by everyone that tell you how to create a cfgrid that is bound to a CFC.

You start with a CFC like with a Get function and an Edit function like:

<cfcomponent output="false">


<cfset THIS.dsn="yourdatabasename">


<!--- Get contacts --->
<cffunction name="getcontacts" access="remote" returntype="struct">
<cfargument name="page" type="numeric" required="yes">
<cfargument name="pageSize" type="numeric" required="yes">
<cfargument name="gridsortcolumn" type="string" required="no" default="">
<cfargument name="gridsortdir" type="string" required="no" default="">

<!--- Local variables --->
<cfset var contacts="">

<!--- Get data --->
<cfquery name="contacts" datasource="#THIS.dsn#">
SELECT contactid, lastname, firstname, email, cool
FROM contacts
<cfif ARGUMENTS.gridsortcolumn NEQ ""
and ARGUMENTS.gridsortdir NEQ "">

ORDER BY #ARGUMENTS.gridsortcolumn# #ARGUMENTS.gridsortdir#
</cfif>
</cfquery>

<!--- And return it as a grid structure --->
<cfreturn QueryConvertForGrid(contacts,
ARGUMENTS.page,
ARGUMENTS.pageSize)>

</cffunction>


<!--- Edit an contact --->
<cffunction name="editcontact" access="remote">
<cfargument name="gridaction" type="string" required="yes">
<cfargument name="gridrow" type="struct" required="yes">
<cfargument name="gridchanged" type="struct" required="yes">

<!--- Local variables --->
<cfset var colname="">
<cfset var value="">

<!--- Process gridaction --->
<cfswitch expression="#ARGUMENTS.gridaction#">
<!--- Process updates --->
<cfcase value="U">
<!--- Get column name and value --->
<cfset colname=StructKeyList(ARGUMENTS.gridchanged)>
<cfset value=ARGUMENTS.gridchanged[colname]>
<!--- Perform actual update --->
<cfquery datasource="#THIS.dsn#">
UPDATE contacts
SET #colname# = <cfif colname eq "cool"><cfif yesnoformat(value) eq "yes">1<cfelse>0</cfif><cfelse>'#value#'</cfif>
WHERE contactid = #ARGUMENTS.gridrow.contactid#
</cfquery>
</cfcase>
</cfswitch>
</cffunction>


</cfcomponent>

Then you create a page with a CFGrid , and javascript to interact with the CFGrid object like this:

<cfajaxproxy cfc="contacts" jsclassname="CFCs.contacts">
<script language="JavaScript">
toggleCool = function(){
   currCool = ColdFusion.getElementValue("contactsGrid","contactForm","Cool");
   //if only there were a ColdFusion.setElementValue()    //then this would be soooo much easier    //instead we do this:    
   //create an instance of the cfc I imported above via cfajaxproxy (coolest tag ever!)    
   var contactsObj = new CFCs.contacts;
   
      //set error handler function       
      contactsObj.setErrorHandler(errorHandler);
   
   //get the gridobject      
   
   var myGrid = ColdFusion.Grid.getGridObject("contactsGrid");
   
   //get the selected row    
   var row = myGrid.dataSource.data.items[getGridIndexById(myGrid,myGrid.getSelections()[0].id)].data;
   
   // now that I have the selected row, I can access the columns buy using the    // name I assigned the cfgridcolumn in uppercase    
   if (row.COOL == "1"){
         row.COOL = "0";
   }else{
      row.COOL = "1";
   }
   
   // Ihave updated the value of my cool row in the grid datasource now I need to    // update the real database. to do this I call the editcontact function in my    // CFC just like the cfgrid would have    
   contactsObj.editcontact('U',row,{COOL:row.COOL});
   
   // Then I call the myGrid.view.refreshRow function which reads from the grid data and    // refreshes what is displayed in the specified row    
   myGrid.view.refreshRow(getGridIndexById(myGrid,myGrid.getSelections()[0].id));
}

// I made a little function here to get the selected rows index by the id
getGridIndexById = function(thisGrid,id){
   for(var i=0,_8=thisGrid.dataSource.data.items.length;i<_8;i++){
      if(thisGrid.dataSource.data.items[i].id==id){return i;}
   }
   return -1;
}

//basic error handler
errorHandler = function(statusCode,statusMsg) {
   alert(statusCode+': '+statusMsg)
}
</script>

<!--- here is a button with an onclick event to change if they are cool or not --->
<input type="Button" value="Toggle Cool Factor" onclick="toggleCool();">
<cfform id="contactForm" name="contactForm">
<cfgrid name="contactsGrid"
format="html"
pagesize="10"
striperows="yes"
selectmode="edit"
bind="cfc:contacts.getcontacts({cfgridpage},{cfgridpagesize},{cfgridsortcolumn},{cfgridsortdirection})"
onchange="cfc:contacts.editcontact({cfgridaction},{cfgridrow},{cfgridchanged})">

<cfgridcolumn name="contactid" display="false" />
<cfgridcolumn name="lastname" header="Last Name" width="100"/>
<cfgridcolumn name="firstname" header="First Name" width="100"/>
<cfgridcolumn name="email" header="E-Mail" width="200"/>
    <cfgridcolumn name="cool" header="Cool Person" width="200"/>
</cfgrid>
</cfform>

And there you have it! Enjoy.

Comments (Comment Moderation is enabled. Your comment will not appear until approved.)
Will Wilson's Gravatar Great post! I was stuggling for ages to find some way to update a cfgrid! Don't suppose you know how to add a selection box as a grid row? Preferrably one that queries a lookup table

P.s. like the working example!
# Posted By Will Wilson | 11/12/07 1:22 PM
Scott Bennett's Gravatar @Will
Check out this article from Todd Sharp:

http://cfsilence.com/blog/client/index.cfm/2006/6/...
# Posted By Scott Bennett | 11/12/07 8:44 PM
sneha's Gravatar Is it possible to render certain rows of a grid in a different color? So far, i've been able to do this only for individual cells.
# Posted By sneha | 8/2/08 3:20 PM
Calvert Acklin's Gravatar Do you know of a way to get the selected rows when multiple selections is enabled -- i.e.
ColdFusion.Grid.getGridObject('contactsGrid').getSelectionModel().singleSelect = false;) ? For example if you want to delete multiple records at one time?
# Posted By Calvert Acklin | 9/28/08 2:50 AM
Calvert Acklin's Gravatar @sneha

You have to override your grid's view to accomplish this. Here's an example:

<style type="text/css">
.red-row{ background-color: #F5C0C0 !important; }
.yellow-row{ background-color: #FBF8BF !important; }
.green-row{ background-color: #99CC99 !important; }
</style>

....

   Ext.override(Ext.grid.GridView, {
getRowClass : function (row, index) {
var cls = '';
var data = row.data;

//Set backgroud color depending on data returned
switch (data.STATE) {
//Yellow bg
case '' :
cls = 'yellow-row'
break;
case 'CA' :
cls = 'yellow-row'
break;

//Green bg
case 'NY' :
cls = 'green-row'
break;

//Red bg                              
case 'DC' :
cls = 'red-row'
break;                                                    
}
return cls;
}
   });
# Posted By Calvert Acklin | 9/28/08 12:39 PM
Calvert Acklin's Gravatar Answered my on question:

To accomplish this you'll need to use the getSelections() function to access the array of selected rows.

I needed to put the values into a single sting. To accomplish this, I used the join() function:

var grid = ColdFusion.Grid.getGridObject("contactsGrid");
var selRecs = grid.getSelectionModel().getSelections();

var sm = grid.getSelectionModel();
var ds = grid.getDataSource();
var selnum = selRecs.length;
var arrSelTemp =new Array(selnum);
var len=selRecs.length;
var str="";

for(var i=0; i<len;i++){
var id = selRecs[i].id;

arrSelTemp[i]= selRecs[i].get("CONTACTID");

//use join() to convert array to a string
str = arrSelTemp.join();

alert("Selected contact ids: " + str);

};
# Posted By Calvert Acklin | 9/29/08 11:39 AM
Mike F.'s Gravatar Scott:
Been working through your example as it is best I've found to help me do what I wan to do. But I keep having a problem with the getGridIndexById function. When the function is called from the var row statement, I get thisGrid.dataSource is undefined. I am very new at using these types of function
and this could be just a newbe issue. Any suggestions? (all script shown below)

<cfajaxproxy cfc="SAM_CTV" jsclassname="dataproxy">
<html>
<head>
<script type="text/javascript">
// create a new JS proxy object for the CFC   
var dataproxy = new dataproxy();
dataproxy.setCallbackHandler(handleResult);
dataproxy.setErrorHandler(errorHandler);

function handleResult(response)
{
   alert(response);
}

// add Button to Toolbar
function init(){
grid = ColdFusion.Grid.getGridObject("getNASRAC");
var gridHead = grid.getView().getHeaderPanel(true);
var tbar = new Ext.Toolbar(gridHead);
tbar.addButton({text:"Update Channel", handler:onChange });
}

function onChange(button,event){
// get Gridobject
var myGrid = ColdFusion.Grid.getGridObject("getNASRAC");
// Get Selected Row
var row = myGrid.dataSource.data.items[getGridIndexById(myGrid.getSelections()[0].id)].data;
// set variables for window output

wKey = row.Hits_Key;
wTier = row.Hits_Tier;
wSource = row.Hits_SourceID;
wSrvType = row.Hits_ServiceProviderType;
wSymbol = row.Hits_Symbol;
wDesc = row.Hits_Name;
   
   ColdFusion.Window.show('chgNASRACChannel');
}

function chgChannelData()
{
   //send data to CFC to add artist, the result will be handled by handleResult function above
   var f = document.frmchgChannelData;
   dataproxy.chgChannelData(
      f.txtKey.value
      ,f.txtTier.value
      ,f.txtSource.value
      ,f.txtSymbol.value
      ,f.txtDescription.value
   );
   ColdFusion.Window.hide('chgNASRACChannel');
   grid.refresh();
}

// create getGridIndexById Function
function getGridIndexById(thisGrid,id){
for(var i=0,_8=thisGrid.dataSource.data.items.length;i<_8;i++){
if(thisGrid.dataSource.data.items[i].id==id){return i;}
}
return -1;
}

//basic error handler
function errorHandler(statusCode,statusMsg) {
alert(statusCode+': '+statusMsg)
}

</script>
# Posted By Mike F. | 2/6/09 6:11 PM
Calvert's Gravatar Mike,
Here is my suggested changes using the getSelections(), which should help you get to the data in a column in a selected row a lot easier:

<cfajaxproxy cfc="SAM_CTV" jsclassname="dataproxy">
<html>
<head>
<script type="text/javascript">
// create a new JS proxy object for the CFC
var dataproxy = new dataproxy();
dataproxy.setCallbackHandler(handleResult);
dataproxy.setErrorHandler(errorHandler);

function handleResult(response)
{
alert(response);
}

// add Button to Toolbar
function init(){
grid = ColdFusion.Grid.getGridObject("getNASRAC");
var gridHead = grid.getView().getHeaderPanel(true);
var tbar = new Ext.Toolbar(gridHead);
tbar.addButton({text:"Update Channel", handler:onChange });
}

function onChange(button,event){
// get Gridobject
var myGrid = ColdFusion.Grid.getGridObject("getNASRAC");
// Get Selected Row
//var row = myGrid.dataSource.data.items[getGridIndexById(myGrid.getSelections()[0].id)].data;
var row = myGrid.getSelections();
// set variables for window output

wKey = row.[0].data.Hits_Key;
wTier = row.[0].data.Hits_Tier;
wSource = row.[0].data.Hits_SourceID;
wSrvType = row.[0].data.Hits_ServiceProviderType;
wSymbol = row.[0].data.Hits_Symbol;
wDesc = row.[0].data.Hits_Name;

ColdFusion.Window.show('chgNASRACChannel');
}

function chgChannelData()
{
//send data to CFC to add artist, the result will be handled by handleResult function above
var f = document.frmchgChannelData;
dataproxy.chgChannelData(
f.txtKey.value
,f.txtTier.value
,f.txtSource.value
,f.txtSymbol.value
,f.txtDescription.value
);
ColdFusion.Window.hide('chgNASRACChannel');
grid.refresh();
}

// create getGridIndexById Function
/*function getGridIndexById(thisGrid,id){
for(var i=0,_8=thisGrid.dataSource.data.items.length;i<_8;i++){
if(thisGrid.dataSource.data.items[i].id==id){return i;}
}
return -1;
}*/

//basic error handler
function errorHandler(statusCode,statusMsg) {
alert(statusCode+': '+statusMsg)
}
# Posted By Calvert | 2/6/09 9:40 PM
Ash Coupland's Gravatar Great article Scott. I managed to get multiple grids having individual buttons per row to update real time permissions for my client having struggled with it for several days. All solved now through this posting.

Many, many thanks!
# Posted By Ash Coupland | 2/8/10 2:36 PM
Debbie G.'s Gravatar How do I dynamically set the color of an individual cell? I also want to set the textcolor/fontcolor to
white if the bgcolor=red otherwise, the textcolor should be set to black.

I've tried the following with no success. It only works if I hard-code the color.
<cfgridcolumn name="MyCol" header="My Column" bgcolor="MyCol">
<cfgridcolumn name="MyCol" header="My Column" bgcolor="CX">
<cfgridcolumn name="MyCol" header="My Column" bgcolor="(CX EQ Green?green:yellow)">
# Posted By Debbie G. | 3/15/10 6:03 PM
Scott Bennett's Gravatar @Debbie,

You have to create an override for this. Take a look a few comments up and you will see a comment from Calvert on how to do this. http://www.coldfusionguy.com/ColdFusion/blog/index...
# Posted By Scott Bennett | 3/15/10 6:38 PM
dan fredericks's Gravatar Hey all,
so, I am trying to use this code to help me with my issue, or my 2 issues. First, I have a cfgird with checkboxes, that seems to make it harder.
I have a submit button, where I need to verify at least one row has a checked checkbox onSubmit.
I have a clear all button that needs to find and uncheck all the checkboxes that may be checked.

I copied the example above to a cf page and tried to run it, and I get the datasource.data is null error just like mike.
how is the datasource.data called/what is it?

Any ideas about how to do what I need to do?

thanks for any help
Dan
# Posted By dan fredericks | 5/4/10 2:02 PM
May May's Gravatar It took me quite a while to get it work, because I didn't notice that calling the column in javascript has to be in CAPS. %^&!@#$$
# Posted By May May | 5/10/10 5:48 AM
Dan Fredericks's Gravatar Hey all -- May May,
I used what you said about Caps, and it worked.
So, would you have any idea about how to help me check all the checkboxes in each row, and also select each row?
I also have to figure out how to run a script off of a checkbox...if I check a row, it selects that row...so if I check 3 rows, those 3 rows are selected.

any help would be great...
# Posted By Dan Fredericks | 5/11/10 11:13 AM
Scott Bennett's Gravatar @Dan,

Are you on CF8 or CF9?
# Posted By Scott Bennett | 5/11/10 11:26 AM
dan fredericks's Gravatar I am using CF 9.
# Posted By dan fredericks | 5/11/10 11:48 AM
dan fredericks's Gravatar Hey all,
Anyone have any ideas about my issues? I am struggling to figure out EXTJS and how to get it to work with Checkboxes in the grid. If the user checks a checkbox, that line needs to be selected...
I know how to do multiple selects with the shift or ctrl keys, but not trigger off a checkbox. I figure that is a listener, but I don't have any idea how to write one. I looked at the examples posted above, but I really don't
understand them.

Any help would be really appreciated.

Dan
# Posted By dan fredericks | 5/13/10 9:39 AM
susan's Gravatar @Dan- had same issue.
ext3 uses getStore() now not getDataSource() + some other changes.
I implemented in CF 8:

var row = myGrid.dataSource.data.items[getGridIndexById(myGrid,myGrid.getSelections()[0].id)].data;
   if (row.ADDED == "N"){
         row.ADDED = " Y";
   }else{
      row.ADDED = "N";
   }
   
And now in CF9 have:
var row = myGrid.getSelectionModel().getSelected();
   if (row.data.ADDED == "N"){
         row.data.ADDED = " Y";
   }else{
      row.data.ADDED = "N";
   }
# Posted By susan | 5/24/10 2:05 PM
Dan Fredericks's Gravatar Not sure exactly how to use the code you posted, so here is my example code:

<script>
function formOnLoad(){

   ColdFusion.Grid.getGridObject('entries2').getSelectionModel().singleSelect = false;
   myGrid = ColdFusion.Grid.getGridObject('entries2')
   var row = myGrid.getSelectionModel().getSelected();
if (row.data.chkbox == "N"){
row.data.chkbox = " Y"; alert("hi1");
}else{ alert("hi2");
row.data.chkbox = "N";
}
}
</script>
</head>
<body>

<cfset t = queryNew('id,name,chkbox','integer,varchar,bit') />
   <cfset queryaddrow(t,1) />
   <cfset querysetcell(t,'id',1) />
   <cfset querysetcell(t,'name','sean') />
   <cfset querysetcell(t,'chkbox',0) />
   <cfset queryaddrow(t,1) />
   <cfset querysetcell(t,'id',2) />
   <cfset querysetcell(t,'name','phillip') />
   <cfset querysetcell(t,'chkbox',0) />
   <cfset queryaddrow(t,1) />
   <cfset querysetcell(t,'id',3)   />
   <cfset querysetcell(t,'name','steve') />
   <cfset querysetcell(t,'chkbox',0) />
<cfdump var="#t#">

<div>
<cfform name="test2">   
   
      <cfgrid name="entries2" format="html" width="600" query="t" height="300" selectmode="edit" >
       <cfgridcolumn name="id" header="Id" select="false" >
       <cfgridcolumn name="name" header="Name" select="false">
       <cfgridcolumn name="chkbox" header="checkbox" type="boolean">
      </cfgrid>

</cfform>      
<cfset ajaxOnLoad("formOnLoad")>
# Posted By Dan Fredericks | 5/25/10 9:43 AM
KJ's Gravatar I have a bindable cfgrid in cf8 that updates just fine (I see the red triangle in the cell). What I need to know is how to refresh the grid after the update so the original cfc that fills the grid runs again to show new updated information. I found these commands but not sure where to put them or how to call them. Should they be in the page or the cfc? ColdFusion.Grid.refresh('mygrid', true) ColdFusion.Grid.getGridObject('MyGrid').render();
# Posted By KJ | 6/1/10 8:55 PM
Yoosaf's Gravatar Thanks a lot Calvert. your post about retrieving data fdrom multiple selected cfgrid has been very useful. it has been of great great help.
# Posted By Yoosaf | 4/16/11 6:57 AM