ColdFusion 8 Grid Context Menus

Word Count: 248

ColdFusion 8 has some great AJAX features built in as we all know. One of the more popular tags is the cfgrid in HTML format. This grid as we know really just wraps the Ext 1.1 framework. One question I see often is how can add some context menus to my grid. This would be both when you click on a row in the grid and on the grids header. This tutorial should clear up some of the questions everyone has been asking. First off I need to say this is not perfect. I do tons of Ext 2.0 work and it works great in 2.0 but there is a minor problem and I am sure after this post someone will point out a fix.

Ok, first thing we need to do is create a basic grid for us to use. I am going to use the cfartgallery datasource that is shipped with ColdFusion 8. Basically we just query our database, create an attribute structure (you don't have to do this I just like it this way) and output our grid. If your not sure about the grid code It is pretty basic, just read up on it.

<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">

<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>

Now that we have our grid we need to do a couple things. First we need to call a JavaScript function after our grid loads. To do this I can simply use the ajaxOnLoad tag. This will tell us to call the init method when the page loads. We will get to this function in a second.

<cfset ajaxOnLoad("init")>

The next thing we need to do is include the necessary files to create menus in Ext. A context menu or right click menu is nothing more than a basic menu in Ext. The reason we need to do this is because this page does not use the menu files only a grid so we need to manually include them. I have also chosen to import the aero theme and the menu stylesheets.

<script type="text/javascript" src="/CFIDE/scripts/ajax/ext/package/menu/menus.js"></script>
   <link href="/CFIDE/scripts/ajax/ext/resources/css/ytheme-aero.css" rel="stylesheet" type="text/css">
<link href="/CFIDE/scripts/ajax/ext/resources/css/menu.css" type="text/css" rel="stylesheet"/>

Now for the real magic. Once the grid is created we can add event listeners to the grid. The way we do that is by getting the grid object and calling its addListener method. One of the listeners the Ext framework exposes is the rowcontextmenu listener. This will tell our grid to to listen for context menus. Here we are just using an anonymous function that gets passed the grid object, the row that was click and the event that caused the context menu.

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

grid.addListener("rowcontextmenu", function(grid, rowIndex, e) {
var record = grid.getDataSource().getAt(rowIndex); // Get the Record
});

}
</script>

Now we need to create our menu. I am just creating 2 basic menu items that have a click handler. When the menu item is clicked the onClick method is called. In the full source you will see this method just displays an alert box. Next we need to stope the browser for showing its default context menu. We do that by using the stopEvent method passed by our Event Object. Finally where do we show this menu, well we can capture where the user right clicked.

var contextMenu = new Ext.menu.Menu();
contextMenu.add({text:"Edit Record",handler:onClick});
contextMenu.add({text:"View Record",handler:onClick});

// Stops the browser context menu from showing. e.stopEvent();
// show menu at contextMenu.showAt(e.xy);

And that is all there is to it. Also, now the removed the browsers context menu we have the ability to right click on the the grids header and display those fancy menus. Now remember I told you it was not perfect. There seems to be a couple of CSS issues but nothing major and something I am sure someone will fix. I have some screen shots below and the full source for the example. Please feel free to drop me a question.



Full Example Code

<html>
<head>
<title>Basic Grid Example</title>

<script type="text/javascript" src="/CFIDE/scripts/ajax/ext/package/menu/menus.js"></script>

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

grid.addListener("rowcontextmenu", function(grid, rowIndex, e) {
var record = grid.getDataSource().getAt(rowIndex); // Get the Record
var contextMenu = new Ext.menu.Menu();
contextMenu.add({text:"Edit Record",handler:onClick});
contextMenu.add({text:"View Record",handler:onClick});

// Stops the browser context menu from showing. e.stopEvent();
// show menu at contextMenu.showAt(e.xy);

});

}
function onClick(){
alert("hello")
}
</script>
</head>
<body>

   <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">
   
   <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")>
   
   

   <cfsavecontent variable="head">
   <link href="/CFIDE/scripts/ajax/ext/resources/css/ytheme-aero.css" rel="stylesheet" type="text/css">
<link href="/CFIDE/scripts/ajax/ext/resources/css/menu.css" type="text/css" rel="stylesheet"/>
   </cfsavecontent>

   <cfhtmlhead text="#head#">

</body>
</html>


Comments

#1 Posted By: Henry Posted On: 3/5/08 2:37 PM
wonderful, that's what I've been looking for for a long while.

Question: how do u hide CFGRIDROWINDEX in header context menu -> Columns ? Without the ability to hide that, it is just not acceptable to use that feature as site user might find that confusing, especially when selectmode="edit"
#2 Posted By: Steve 'Cutter' Blades Posted On: 3/5/08 4:25 PM
@Dan - Great post. Quick question though. Wouldn't it have been better to use the CFAjaxProxy tag to import the menu.js and .css, so as to obfuscate the direct path to your CFIDE?
#3 Posted By: Jared Shields Posted On: 3/5/08 10:16 PM
Importing the scripts that way wouldn't really make a difference. If you go to any CF page that uses AJAX components, and view the source, it dumps the script path on the page in exactly the same manner...
#4 Posted By: xavier Posted On: 4/7/08 2:03 AM
I have a listener to listen to the grid edits to keep a <Cfdiv division updated with the current status, the current status coming in from a database query. I am using the "afteredit" event to do this as shown below:
grid.addListener("afteredit", function(e){
ColdFusion.navigate('stats.cfm', 'statsDiv');
});
Looks like the afteredit is fired after the grid edit but before the database update happens and hence I don't get the status after the database update. Any idea how this can be done?
#5 Posted By: Gary Habermann Posted On: 4/17/08 1:18 PM
I have copied you example but the context menus will not appear. I do not see any errors using the ?CFDEBUG, but it does not look like the listener is working
#6 Posted By: Dan Vega Posted On: 4/17/08 1:20 PM |
Author Comment
You copied the full example code right? You are running ColdFusion 8? I would open firebug and see if it gives you anymore insight into what may be happening.
#7 Posted By: Gary Habermann Posted On: 4/17/08 2:35 PM
Yes it is the full example I cut it from the full example I copy from the "full example code box".

Server Product ColdFusion
Version 8,0,0,176276
Edition Enterprise

When I click on the row the follow message appears in the CFDEBUG window:
info: widget: Firing selection change event for grid id: UserDocGrid

I am getting fire bug now.

Thanks
Gary
#8 Posted By: Chad Ramey Posted On: 4/30/08 11:18 AM
Has any one experienced any issues with the context menus showing the list-style circle?
#9 Posted By: Dana Posted On: 5/1/08 9:38 AM
Help, I can't get this to work. I copied exactly what you have. The grid will come up, but when I select an item from the grid, nothing happens. I've turned on cfdebug, and when I select an item from the grid, I get the following.

info:widget: Firing selection change event for grid id: ArtistGrid

Could someone please help. I am not using the c drive, I am using a different drive letter, I didnt know if that made a difference.
#10 Posted By: Chad Ramey Posted On: 5/1/08 9:40 AM
I had the same trouble. its part of the comments in the script that was causing it. This:

// Stops the browser context menu from showing. e.stopEvent();
// show menu at contextMenu.showAt(e.xy);

should be like this.

// Stops the browser context menu from showing.
e.stopEvent();
// show menu at
contextMenu.showAt(e.xy);
#11 Posted By: Dan Vega Posted On: 5/1/08 9:42 AM |
Author Comment
I will have to fix that, when I post JavaScript it does not format it correctly. Thanks Chad!
#12 Posted By: Chad Ramey Posted On: 5/1/08 9:43 AM
I figured out the answer to my own question.

Has any one experienced any issues with the context menus showing the list-style circle?

Add this to the <head> of your page.

<style>
.x-menu-list{
margin: 0px; padding: 0px; list-style: none; background: none !important;
}
</style>
#13 Posted By: Dan Vega Posted On: 5/1/08 9:46 AM |
Author Comment
Todd Sharp Answered that question on another post.
#14 Posted By: Chad Ramey Posted On: 5/1/08 9:47 AM
Has anyone seen how to adding a "group by" option for the menus?
#15 Posted By: Dana Posted On: 5/1/08 10:50 AM
Thanks,
Chad, I completely over looked that.


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.