CFGrid Event Listeners

Word Count: 1740

As you all know by now the grid in ColdFusion 8 is powered by the Ext framework. If you dive into the documentation you will find out that there is more that you can do with it then advertised. We have been looking at ways to customize the grid, today we will learn about event listeners. The grid has the ability to announce events as they are happening even if you are not listening for them. Events can include clicking on a row double clicking on a cell or even using a keyboard shortcut. Just knowing that the gird announces these events will do you no good, you need the ability to listen for them.

The grid gives you 2 methods to listen for events. The following methods will append an event handler to this component the on method is just shorthand for addListener.

  • addListener( String eventName, Function handler, [Object scope], [Object options] ) : void
  • on( String eventName, Function handler, [Object scope], [Object options] ) : void

These methods belong to the grid so to use them you need to have the grid object. Fortunately for you ColdFusion provides an easy way to get the grid object. If you have been following my examples than the following should look familiar. I am using the cfartgallery data source that ships with CF8 so you can follow along at home. The code below will run a query and create a grid with the name of ArtistGrid. The name is important because that is how we will get our grid object later on. Finally the last line will call the init method when the page loads.

<cfquery name="getArtists" datasource="cfartgallery">
   SELECT artistId, firstname, lastname, address, city, state, postalcode, email
   FROM Artists
   </cfquery>
   
   <cfset args = structNew()>
   <cfset args.name = "ArtistGrid">
   <cfset args.format = "html">
   <cfset args.query = "getArtists">
   <cfset args.stripeRows = true>
   <cfset args.selectColor = "##D9E8FB">
   <cfset args.selectOnLoad = false>
   
   <cfform>
      <cfgrid attributeCollection="#args#">
         <cfgridcolumn name="artistid" display="false">
         <cfgridcolumn name="firstname" header="First Name">
         <cfgridcolumn name="lastname" header="Last Name">
         <cfgridcolumn name="email" header="Email Address">
         <cfgridcolumn name="address" header="Address">
         <cfgridcolumn name="city" header="City">
         <cfgridcolumn name="state" header="State">
         <cfgridcolumn name="postalcode" header="Zip">
      </cfgrid>
   </cfform>
   
   <cfset ajaxOnLoad("init")>

Now that our grid is setup we can setup our init method. Remember I said ColdFusion makes it easy, I was not lying, the getGridObject will get our grid for us.

<script type="text/javascript">
function init(){
//get the grid component grid = ColdFusion.Grid.getGridObject("ArtistGrid");
</script>

Now that we have our grid object we can start adding listeners. Lets say we wanted to call a method when a row is clicked. Here we are listening to for a row to be clicked and then calling a method named editArtist. Our editArtist method also get some information about the row being clicked. So How did i know what information would be passed?

<script type="text/javascript">
function init(){
   //get the grid component       grid = ColdFusion.Grid.getGridObject("ArtistGrid");
      
      //Fires when a row is clicked       grid.addListener("rowclick",editArtist);
      
}

function editArtist(grid,rowIndex,e){
   var record = grid.getDataSource().getAt(rowIndex);
   console.log(record);
}

</script>

If we look at the documentation for the grid event listeners we will get some more details about them. The arguments are what will get passed to use when that event is fired.

  • bodyscroll : ( Number scrollLeft, Number scrollTop ) - Fires when the body element is scrolled
  • cellclick : ( Grid this, Number rowIndex, Number columnIndex, Ext.EventObject e ) - Fires when a cell is clicked
  • cellcontextmenu : ( Grid this, Number rowIndex, Number cellIndex, Ext.EventObject e ) - Fires when a cell is right clicked
  • celldblclick : ( Grid this, Number rowIndex, Number columnIndex, Ext.EventObject e ) - Fires when a cell is double clicked
  • click : ( Ext.EventObject e ) - The raw click event for the entire grid.
  • columnmove : ( Number oldIndex, Number newIndex ) - Fires when the user moves a column
  • columnresize : ( Number columnIndex, Number newSize ) - Fires when the user resizes a column
  • contextmenu : ( Ext.EventObject e )The raw contextmenu event for the entire grid.
  • dblclick : ( Ext.EventObject e ) - The raw dblclick event for the entire grid.
  • dragdrop : ( Grid this, Ext.GridDD dd, String targetId, event e ) - Fires when dragged row(s) are dropped on a valid DD target
  • dragenter : ( Grid this, Ext.GridDD dd, String targetId, event e ) - Fires when the dragged row(s) first cross another DD target while being dragged
  • dragout : ( Grid this, Ext.GridDD dd, String targetId, event e ) - Fires when the dragged row(s) leave another DD target while being dragged
  • dragover : ( Grid this, Ext.GridDD dd, String targetId, event e ) - Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dr...
  • enddrag : ( Grid this, Ext.GridDD dd, event e ) - Fires when a drag operation is complete
  • headerclick : ( Grid this, Number columnIndex, Ext.EventObject e ) - Fires when a header is clicked
  • headercontextmenu : ( Grid this, Number columnIndex, Ext.EventObject e ) - Fires when a header is right clicked
  • headerdblclick : ( Grid this, Number columnIndex, Ext.EventObject e ) - Fires when a header cell is double clicked
  • keydown : ( Ext.EventObject e ) - The raw keydown event for the entire grid.
  • keypress : ( Ext.EventObject e ) - The raw keypress event for the entire grid.
  • mousedown : ( Ext.EventObject e ) - The raw mousedown event for the entire grid.
  • mouseout : ( Ext.EventObject e ) - The raw mouseout event for the entire grid.
  • mouseover : ( Ext.EventObject e ) - The raw mouseover event for the entire grid.
  • mouseup : ( Ext.EventObject e ) - The raw mouseup event for the entire grid.
  • render : ( Grid grid ) - Fires when the grid is rendered
  • rowclick : ( Grid this, Number rowIndex, Ext.EventObject e ) - Fires when a row is clicked
  • rowcontextmenu : ( Grid this, Number rowIndex, Ext.EventObject e ) - Fires when a row is right clicked
  • rowdblclick : ( Grid this, Number rowIndex, Ext.EventObject e ) - Fires when a row is double clicked
  • startdrag : ( Grid this, Ext.GridDD dd, event e ) - Fires when row(s) start being dragged

And that is how we are able to find out more information about the event that is happening. In our editArtist method we are getting passed the rowIndex, this allows us to look up what record what clicked. As you can see event listeners can be very powerful and just another way that you can customize your grid components. Please feel free to leave me any questions you might have about them.

Comments

#1 Posted By: Michael White Posted On: 3/20/08 12:58 PM
your inline comments messed me up when I tried to run the code. the whole line is commented out when you put the // in front, right?
#2 Posted By: Dan Vega Posted On: 3/20/08 1:00 PM |
Author Comment
Ya just move the grid = down a line.
#3 Posted By: Jeff Self Posted On: 3/20/08 4:45 PM
Love these articles! You have solved almost every question I've had about grids. One last issue remains for me and maybe you know of a way to resolve this. Do you know of a way to allow text to wrap in a field in the grid? I'd like to include comments in a grid but I am not able to right now since the comments get cut off because I haven't found a way to wrap the text.
#4 Posted By: Kay Smoljak Posted On: 3/21/08 12:10 AM
I love these articles - great work Dan! When's the book coming out? :D
#5 Posted By: Dan Vega Posted On: 3/21/08 10:28 AM |
Author Comment
@Jeff - Have you tried to set a specific width for the column?

@Kay - Thanks so much. No plans for a book just yet! ha ;)
#6 Posted By: Daniel Posted On: 3/22/08 9:03 AM
It is wonderful I learnd so much reading your posts.

Is it possible to know if customer resize or move columns and save this onchange?
#7 Posted By: Mark D Posted On: 3/31/08 12:00 PM
I have recently found your site as I started digging into the CF8 UI tags. Great stuff here. I want to not allow a user to resize columns in a cfgrid. I have my functiosn written so that I know when the columnresize is called but I am not sure what to do from there. I tried an editEvent.cancel, but editEvent isn't defined. almost there, just need a little push. Thanks.
#8 Posted By: mp Posted On: 5/5/08 12:55 PM
When I do the following: <cfgridcolumn name="Emp_ID" display=true header="Acme <br /> Employee <br /> ID"/> to have the column header appear on multiple lines, instead of one line, the color of the header changes from grey to tan. Is there any way to add multiple lines to the header and keep the grey color? Allowing the text to wrap would probably work. Does anyone know how to do this? I've tried to set a column width as you suggested Dan, but this doesnot make the text wrap.

Thanks in advance,
mp
#9 Posted By: JeffG Posted On: 5/17/08 9:34 AM
Dan -
I love your blog and always learn something from your posts.

I have run across something troubling and I hope you can help.
I have been doing some work with cfgrids bound to cfcs.
The site is built on a CF8 server using Fusebox55 as a framework.
I have noticed that each cfgrid consumes a lot of memory, [4-10mb] even when there is only a couple of records.
This memory allocation does not get released when you go to a different page in the site.
The memory is not recovered until the last browser belonging to the session is closed.
If you bounce around in a session for a while with this kind of consumption eventually [not a long time really] the browser crashes.
This occurs in both IE and FF3.

Example: I have several different grids on several tabs on 1 page of the application I am developing. I also have a separate browser that opens with a grid in it [a help index]. What I have seen is that if you go to the section of the site with the grids a block of memory gets consumed each time the page is opened, but it is not released if you navigate away. Spawn the separate window [the help system] a block of memory is consumed. Close and re-open the help window and 4-10mb of memory is consumed but not released each time.

I think this looks like it relates to issues with event listeners generating memory leaks and becoming orphans if they are not destroyed.
I know that event listeners should be destroyed.
But I have not read nor can find nothing about cleaning up after a cfgrid when you go to close a web page.

It is definitely related to the cfgrid I can trace it that far.

Here is a thread where others are discussing the exact same behavior.
http://groups.google.com/group/macromedia.coldfusi...

Have you seen this as an issue?

On a related topic how do I destroy the listeners I create that are watching for rowclick etc.
I read your comment in a post about creating a listener to destroy() cfwindow instances but I can't see how I extend that concept to my cfgrids or to my other listeners.

I am faced with the fact that I will have to remove cfgrd from my project and develop a different solution if this is not correctable.

Do you have any suggestions.

Thanks in advance for any suggestions you may have.

Jeff G
#10 Posted By: Matt Gifford Posted On: 5/22/08 10:42 AM
Hi Dan

This is great. Thank you so much.
I'm using the eventListener rowclick, and am receiving the rowIndex.

Does anyone know how I can pass across a value from the query (that row's ID) to the script, so that I can use it in a query call?
#11 Posted By: Dan Vega Posted On: 5/22/08 10:47 AM |
Author Comment
I do this when I have a UUID as the primary key. In a grid you can set a columns visibility to hidden but the id is still present in the object. In your row click handler you should still have access to that variable.
#12 Posted By: Matt Gifford Posted On: 5/22/08 10:57 AM
Thanks Dan.

How do I access that variable from the Listener?
#13 Posted By: Dan Vega Posted On: 5/22/08 11:00 AM |
Author Comment
IF you check out the docs from above (ExtJS 1.1 docs) you will see that the row click will pass the grid object, the rowIndex & the event object. With that information we could do something like this.

function editArtist(grid,rowIndex,e){
   var record = grid.getDataSource().getAt(rowIndex);
   console.log(record);
}
#14 Posted By: Matt Gifford Posted On: 5/22/08 11:08 AM
Thanks again Dan.

I'm really sorry, I'm still stuck on this one. I can see it passing the object via the record variable, but how do I access the individual grid variables from this?

For example, I want to retrieve the UUID from that selected row.

Any help would be greatly appreciated.
#15 Posted By: Dan Vega Posted On: 5/22/08 11:18 AM |
Author Comment
No big deal at all Matt. I had a huge problem with this when I first playing around with it. First thing I would do is use Firebug to inspect the object. The console.log(record) logs the record object to so you can see what it is made up of. In my example I could do this

var row = grid.getDataSource().getAt(rowIndex);
var artistId = row.data.ARTISTID;
#16 Posted By: Brian Posted On: 7/30/08 9:57 PM
Thanks for the post. I'm using CF 8.01 and html cfgrid. The rowclick, rowdblclick and keypress events worked for me. However the render did not. Also what I really need is a way to capture the event of onSelect (regardless how it is accomplished even on grid load, or paging, or using up/down keys). I know how to get or go to the selected row using the selection model, just not capture the change event itself. Ideas?
#17 Posted By: Brian Posted On: 7/30/08 11:08 PM
I just saw the answer to part of this question. To capture the paging and load event see http://blog.cutterscrossing.com/index.cfm/2008/1/9.... I still have a problem with the user's up/down keys.
#18 Posted By: sneha Posted On: 8/1/08 8:21 PM
Hi i need some help with this:
I have two grids (grid1 & grid2). I want grid2 results to be filtered based on grid1 selection (which i was able to do) but initially on page load i want all records to show up on grid2.
This is what i have:
function init(){
//window.filterParam = '';
grid = ColdFusion.Grid.getGridObject("grid1");
grid.addListener("rowclick",setValue);
}
function setValue()
{
//window.filterParam = '';
var grid = ColdFusion.Grid.getGridObject("grid1");
var record = grid.getSelections();
window.filterParam = record[0].data.FIRSTNAME;

var grid2 = ColdFusion.Grid.getGridObject("grid2");
grid2.refresh();
}
function getValue()
{
return window.filterParam;
}

And the bind attribute for grid2 has:
<cfgrid format="html" name="employeeGrid"
bind="cfc:employeeService.getData({cfgridpage},{cfgridpagesize},
   {cfgridsortcolumn},{cfgridsortdirection},getValue())"

Whats happening is, on page load all records display on grid2. But when a row from grid1 is clicked, still grid2 shows all records. Only when a second row from grid1 is clicked, results pertaining to previous grid1 selection (not current selection) get filtered in grid2.

I printed 'window.filterParam' when every grid1 row is clicked and it seems to be getting the right value, but for some reason grid2 results aren't getting refreshed.

please someone help!!
#19 Posted By: greg Posted On: 10/31/08 4:20 PM
Really nice work.
#20 Posted By: Bob R Posted On: 12/11/08 11:12 AM
Great Post! This has really helped.

I do have one question though, is there a way to tell what cell a user has clicked on. I want to open a window when a user clicks on a cell, unless it is the first cell which contains a check box.

Thanks for you help.
#21 Posted By: Bob R Posted On: 12/11/08 3:03 PM
Nevermind. I got it.
#22 Posted By: Tones411 Posted On: 2/18/09 11:09 AM
Make sure the javascript init() is in the head area.

Here's a trick to get it into the head area if you are using some kind of template system:

<cfsavecontent variable="javascript">
<script type="text/javascript">
function init(){
...
}
</script>
</cfsavecontent>
<cfhtmlhead text="#javascript#">

<cfset ajaxOnLoad("init")>
#23 Posted By: Gary Habermann Posted On: 6/20/09 11:53 PM
IS it possible to allow users to dynamically hide and show a column. I have a grid with several fields, of summary data, I would like to give user the abliity to ckick on a "show desc" button, which would add the description column to the grid.


Post Your Comment







Show Captcha

If you subscribe, any new posts to this thread will be sent to your email address.

Copyright © 2007 Dan Vega | BlogCFC was created by Raymond Camden. This blog is running version 5.8.001.