ColdFusion 8 Grid Context Menu Part II

Word Count: 435

In our previous example I showed you how you could create a context menu using cfgrid and some Ext magic. Now I would like to take that example a step further. I good use case for a context menu on the grid is giving the user quick access to view or edit the record just by right clicking on the row. Using our new found knowledge and CFWindow this will turn out really nice.

Most of the code is the same from the last example so if you do not understand it click on the link at the beginning of this article. If you remember from our previous example we created a rowcontextmenu event listener for our grid. The important thing to understand is that this method will pass us the grid object, the row that was clicked and the event object. Using the rowIndex we can get the data for the row being clicked. We can use the grid object, get the datasource (data store) and get the row at the index passed in by our event listener.

<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 that we have the record I want to setup a couple of local variables. I am going to use these variables when I open my edit window so It is easier if we just set them now.
var artistFullName = record.data.FIRSTNAME + " " + record.data.LASTNAME;
var artistId = record.data.ARTISTID;
Now I am going to setup a menu item that will display the text Edit Record and use an inline function. In the body of the this method you can see that we are using ColdFusion to create a new window. As part of the title I want to display the artist name and I also want to pass the id of the artist to our edit url. We can just use the local variables we created above.
var contextMenu = new Ext.menu.Menu();
contextMenu.add({text:"Edit Record",handler:function(){
   
   ColdFusion.Window.create("editArtist","Edit Artist " + artistFullName,"editArtist.cfm?id="+artistId,{
      modal:true,
      width:600,
      height:400,
      center:true
   });
   
}});
Nothing fancy going on here but I think it is perfect for quick and dirty views or edits. A couple of notes that might be of interest though. Remember to use cfajaximport to import the tag cfwindow or you will not be able to use it. Also if all this JavaScript does not make sense, I highly suggest that you chekout FireBug and the console.log() method will become your second favorite peice of code next to cfdump! The full source code for the example is below.
<html>
<head>
<title>Edit Row 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
//artist name var artistFullName = record.data.FIRSTNAME + " " + record.data.LASTNAME;
var artistId = record.data.ARTISTID;

var contextMenu = new Ext.menu.Menu();
contextMenu.add({text:"Edit Record",handler:function(){
   
   ColdFusion.Window.create("editArtist","Edit Artist " + artistFullName,"editArtist.cfm?id="+artistId,{
      modal:true,
      width:600,
      height:400,
      center:true
   });
   
}});

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


console.log(record);
});

}
</script>
</head>
<body>
   
   <cfajaximport tags="CFWINDOW">

   <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: Chris Dawes Posted On: 3/5/08 1:02 AM
Dan, you do realise what happens when you crack out the Javascript for real... you just get hooked and want to do more... and more...
#2 Posted By: Dan Vega Posted On: 3/5/08 7:49 AM |
Author Comment
Believe me I know! 1 year ago I knew nothing about JS. Know I think I know a little more... ha :)
#3 Posted By: Trond Ulseth Posted On: 3/5/08 11:23 AM
Awesome stuff Dan!

I was in need of something similar, but to open the window when clicking the row, without the need for a context menu. I was able to do this, but I wondered if you could tell me how I would get the new window by left-click rather than right-clicking the mouse?
#4 Posted By: Dan Vega Posted On: 3/5/08 11:25 AM |
Author Comment
Trond,
It is not only possible but pretty easy as well. I will write something up today, stay tuned! If you need this right now you can email me.
#5 Posted By: Mike Posted On: 3/5/08 6:23 PM
Looks like the window is not getting updated after the first instance. When I right click on a record and click on "Edit Record", it works the first time, but all subsequent attempts open the window with the data (artistID) from the first try.
When I look at it in Firebug, it looks like only the first click does a GET. Is the window just getting re-opened with it's old data in it?
#6 Posted By: Dan Vega Posted On: 3/5/08 6:57 PM |
Author Comment
I will look into this for you Mike, but just knowing how windows work I would say that the default behavior is to hide the window. We probably need to it to destroy the window on close. I know how this works in Ext but I will have to look into this in CF8.
#7 Posted By: Jared Shields Posted On: 3/5/08 10:21 PM
ColdFusion.Window.getWindowObject("editArtist").destroy();
#8 Posted By: Dan Vega Posted On: 3/5/08 10:24 PM |
Author Comment
You either have to destroy the window as Jared points out or create a unique window each time. To create a new window each time the name has to be unique. Personally I would just destroy the window.
#9 Posted By: Trond Ulseth Posted On: 3/6/08 3:59 AM
After some Googling around I found the solution to be rather simple - as you said Dan :)

I replaced "rowcontextmenu" with "rowclick" and there it was :)

Anyways - I'm building a UI for an application using CF's buildt in extjs capabilities now - and I'm learning a LOT from your blog. Thank you for sharing.
#10 Posted By: Trond Ulseth Posted On: 3/6/08 10:04 AM
Do you know if it's possible to make it so that "rowclick" and "rowcontextmeny" does not fire if one clicks one the first column in a grid?

(I swear I try to Google and wade my self through extjs documentation before asking all this stupid questions :)
#11 Posted By: Dan Vega Posted On: 3/6/08 11:28 AM |
Author Comment
@Trond - Do you mean the first row? Why would you not want to allow the first row to be clicked?
#12 Posted By: Trond Ulseth Posted On: 3/6/08 11:38 AM
Dan - I mean the first column. In the first column of each row I have a check box, and I don't want a cfwindow to appear when I click the check box.
#13 Posted By: Jeff Self Posted On: 3/6/08 1:16 PM
Great work Dan. I have been working on this exact problem this week.

@Tron,
What did you do to get rowclick to work?
#14 Posted By: Michael White Posted On: 3/6/08 1:31 PM
The first time you try to destroy a window it doesn't exist and throws an error. how do you check to see if it exists first?
#15 Posted By: Dan Vega Posted On: 3/6/08 1:41 PM |
Author Comment
Why are you trying to destroy a window if it does not exit? Can you please explain what you are trying to do? You should be able to do this.

win = ColdFusion.Window.getWindowObject("mywin");
if(win){
//it is available
}
#16 Posted By: Michael White Posted On: 3/6/08 2:03 PM
Jared Shields posted the command to destroy the window in order to get a new windows instead of just showing the old window. this works great once there is a window but the the first time you use the context menu to bring up your "editArtist.cfm?id="+artistFullName the window doesn't yet exist. I am working on the assumption you would put Jared's command right before the ColdFusion.window.Create line
#17 Posted By: Michael White Posted On: 3/6/08 2:05 PM
forgot to mention: Dave Ferguson uses try/catch but I must not be using it right.
http://blog.dkferguson.com/index.cfm/2008/2/6/alte...
#18 Posted By: Dan Vega Posted On: 3/6/08 2:09 PM |
Author Comment
I guess I am just wondering why you are trying to destroy a window that has not been created. Can you provide some code?
#19 Posted By: Michael White Posted On: 3/7/08 9:04 AM
the code is your own... above... check out comment 5,7,8. now I can easily use unique window names, that's what I'm doing now, but I want to destroy instead but you can't destroy a windows that doesn't exist, you get an error, so you have to check if the window is there first.
#20 Posted By: Dan Vega Posted On: 3/7/08 9:11 AM |
Author Comment
That is what I was trying to get at though. The destroy method should only be used when the user is closing the window. I would add a listener for the window and listen for the hide method, when the window is hidden destroy it.

win.addListener("hide",function({ColdFusion.Window.getWindowObject("editArtist").destroy()});

I hope this makes sense and you are right you should not be trying to destroy the window if it does not exist yet.
#21 Posted By: Michael White Posted On: 3/7/08 9:20 AM
Brilliant! you're a life saver
#22 Posted By: Jeff Self Posted On: 3/10/08 10:46 AM
Dan,

I'd be interested in seeing how you can call a cfwindow by clicking on the row rather than using a context menu. I'm working on something now that I wanted to use a pop-up window that contained an edit form, but I can't figure a way to do it with a grid. But I'll be glad to use a cfwindow instead of a pop-up window.
#23 Posted By: Dan Vega Posted On: 3/10/08 10:50 AM |
Author Comment
@Jeff,
I will try and write a full article on event listeners but until then try this. I have not tested this but it should work.

function init(){
   //get the grid component
      grid = ColdFusion.Grid.getGridObject("ArtistGrid");
//row click
grid.addListener("rowclick",function(grid,rowIndex,e){
   var record = grid.getDataSource().getAt(rowIndex);
   
});
}
#24 Posted By: Cliff Posted On: 4/10/08 11:28 PM
Dan, in post #20 you said to add the following line of code:
win.addListener("hide",function({ColdFusion.Window.getWindowObject("searchResults").destroy()});

Where do I put this in relation to the following? The code below works just fine but like post #5 states I am getting the same results each time I open the cfwindow. I have tried to put the listener in various places but when I do, the right click menu stops working altogether for some reason.


<script type="text/javascript">
   function init(){
   
   grid = ColdFusion.Grid.getGridObject("searchResults");   
   
   grid.addListener("rowcontextmenu", function(grid, rowIndex, e) {
      var record = grid.getDataSource().getAt(rowIndex); // Get the Record
      
      var resName = record.data.RESTAURANTNAME;
      var resID = record.data.ID_RESTAURANT;
      
      var contextMenu = new Ext.menu.Menu();
      contextMenu.add({text:"Edit Record",handler:function(){

       ColdFusion.Window.create("editRes","Edit " + resName,"http://www.myfooddelivery.net/admin/manage_restaur...,{ modal:true, width:600, height:400, center:true });
      
      }});
      
      e.stopEvent();// Stops the browser context menu from showing.
      contextMenu.showAt(e.xy);// show menu at
      console.log(record);
   });

   }      

</script>
#25 Posted By: Dan Vega Posted On: 4/10/08 11:33 PM |
Author Comment
It has nothing to do with the grid listener. The problem here is that every time you create a window you are creating a window the an id of editRes. A simple solution is to make sure that id is unique every time you create the window. An easy way to do that is .create("editRes-"+resId,"Edit "... The other solution involves adding an event handler to the window itself. If you would like to do it the other way ping me and I can show you how.
#26 Posted By: Cliff Posted On: 4/11/08 6:58 AM
Dan,
You rock! it works.
Thanks for the response.
#27 Posted By: nelson Posted On: 4/30/08 2:28 PM
Anyone have any luck on fixing the CSS bug? The little bullet points in IE are driving me nuts!
#28 Posted By: todd sharp Posted On: 4/30/08 2:48 PM
Try adding this style to your <head>


<style>
.x-menu-list{
margin: 0px; padding: 0px;
}
</style>
#29 Posted By: Dave Posted On: 8/18/08 12:26 AM
ColdFusion.Window.create("Edit" + resId,"Edit Artist " + artistFullName,"editArtist.cfm?id="

Whenever i add the resID infront of Edit to prevent duplicate window ID's from being generated, i get redirected to the top of the page (#) whenever the context menu is clicked...Any ideas?
#30 Posted By: Dave Posted On: 8/18/08 12:57 AM
Nevermind. Im a donk...I set the var to my specific var and not ResID which is specific to another case. All is well. THanks
#31 Posted By: Joshua Cyr Posted On: 11/10/09 1:35 PM
Quick note for CF 9. Lots of things have changed. Thanks to Mr Vega I see that one line needs to be changed.

var record = grid.getDataSource().getAt(rowIndex); // Get the Record

Should now be:
var record = grid.getStore().getAt(rowIndex); // Get the Record
#32 Posted By: Raj Posted On: 2/9/10 9:25 PM
Dan, I am trying to acheive what you mentioned in post 25. I am assuming that win.addListener("hide",function({ColdFusion.Window.getWindowObject("searchResults").destroy()}); needs to be added on the cfwindow. But not sure how. I am a beginner on cfwindow. So can you please tell me how to do this. Thanks in advance.


Post Your Comment

Leave this field empty







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.