Reacting to grid row selection
This week must be grid week. First we have Bruce Phillips' post on cfgrid last night, and today Todd Sharp posted on it as well. I thought I'd follow the crowd and share a tip as well. How do you do something (anything) when a user clicks on a grid, specifically when using the new HTML cfgrid in ColdFusion 8?
Technically there isn't a attribute that you can add to the grid itself. However, other form fields can easily bind to the grid itself. So if you wanted to build an edit form, for example, that is pretty easy (and again, see Bruce Phillips' post). But what if you wanted more fine grained control? This is where CFAJAXPROXY comes in.
Now if you are like me - you looked at the docs on CJAJAXPROXY and were impressed with how cool it is to be able to create a connection to a CFC. That's amazing, and in my mind, I think it is the most impressive new feature in ColdFusion 8.
But what people may miss (I know I did!) is that CFAJAXPROXY has a whole other... "mode" we shall call it, that lets the tag act in a complete separate manner. In fact, it is so different I'm not quite sure why another tag wasn't made, like CFBIND for example. This other mode takes one main attribute, bind. You can also use a onSuccess and onError attribute. In this mode, the tag simply acts as a listener. So image my grid is named entries. I can bind to it like so:
<cfajaxproxy bind="javascript:noteChange({entries.title})">
All this says is - when the grid changes - call a JavaScript function and pass the value of the Title column. I could also use a CFC or CFM bind as well, but you get the idea. Again, I think CFBIND would be a better name since in this form the tag isn't creating a proxy object for a remote CFC. But that's neither here nor there - lets get back to the original question - how do I react to a grid change?
First you need to figure out what values you want. In my code sample above, I grabbed the title column. If I wanted something different, like ID, I'd do:
<cfajaxproxy bind="javascript:noteChange({entries.id})">
Or I can do both:
<cfajaxproxy bind="javascript:noteChange({entries.title},{entries.id})">
Now for a complete example:
<cfajaxproxy bind="javascript:noteChange({entries.title},{entries.id})">
<script>
function noteChange(title,id) {
alert(title+' '+id);
}
</script>
<cfquery name="entries" datasource="blogdev">
select *
from tblblogentries
limit 0,10
</cfquery>
<cfform name="test">
<cfgrid autowidth="true" name="entries" format="html" query="entries" pageSize="10">
<cfgridcolumn name="id" display="false">
<cfgridcolumn name="title" header="Title">
<cfgridcolumn name="posted" header="Posted">
</cfgrid>
</cfform>
In this example I'm loading up my HTML grid with a query (yes, you don't have to use Ajax for HTML grids). On the top of my template I bound my JavaScript function to the entries grid. Whenever I selected an entry in my grid, an alert will be fired.
I want to point out one last thing. Take a look at the first cfgridcolumn. Why do I have a column that I don't bother displaying? When you specify the columns to show - you are also limiting the data actually stored in the grid. If I didn't have that hidden column there, I wouldn't be able to use the ID column in my bind.
Comments
Is their a way to add a image to the data grid?
Your this example is coooooooooooool.
Abul
<cfloop query="getData">
<cfset querySetCell(getData, "test", "<img src='http://www.coldfusionjedi.com/images/me.jpg'>", currentROw)>
</cfloop>
I'll do a full demo later today.
@Will: I don't think so.
I just added the code to the bottom of the demo page. Let me know if you have any questions that I can help with.
I also did a demo with two connected grids. Here is a demo of it:
http://demo.thinksys.com/cf8/cfgrid/2grids.cfm
SWEET! Thanks for doing this. Just so others can follow along, Steve Sequenzia has offered two code examples for binding data 1) to a cfdiv, and 2) to a second cfgrid on the same page, based on a cfgrid row click (awesome):
1) cfgrid-to-cfdiv example:
http://demo.thinksys.com/cf8/cfgrid/contacts.cfm
2) cfgrid-to-cfgrid example:
http://demo.thinksys.com/cf8/cfgrid/2grids.cfm
Thanks Steve! I'm sure this will be very helpful for readers.
If you do a 'veiw source' on those pages, though, you can see that there are a bunch of .js files callled at the top. Anyone know how much file size overhead this stuff is adding??
HTML: 3.1 kb
CSS: 6.7 kb
Javascript: 435 kb!
Wow. All these cool AJAX tricks that you can do with CF8 look cool. But a simple page like this weighing in at almost a half megabyte, you better hope none of your users are still on dialup....
http://alex.dojotoolkit.org/shrinksafe/
I did it for the Spry js files and they all still work perfectly but are a fraction of their original size.
(original blog link to Rey's post : http://www.reybango.com/index.cfm/2007/7/22/Compre...)
Nice post. However, I think I've found a bug. If you click on a title, the javascript popup displays with the title and the ID just fine. However, if you close the popup window, then click on the same title again, no popup appears. I know this is a minor issue, however, I believe some users will invariably close the window, then want to see the same info again.
How to get around this one?
Thanks,
Peter
<cfajaxproxy bind="javascript:noteChange({entries.title@mousedown},{entries.id@click})">
but it didn't work. Notice I tried both mousedown and click.
I was studying the code, and could not duplicate the examples posted, can you Steve Sequenzia please post a zip of the files, so that I can study the source, along with any one else for the matter?
a studying student,
Camilo
http://demo.thinksys.com/cf8-grid-examples.zip
Let me know if I can help.
-Steve
the code could not find the cfc
it is in the same directory, and still error. But I have the code, and this has greatly help me out. thanks for giving me the leg up with this ;-)
There is a lot that I can learn from from everyone here !
<script>
function UpdateFromGrid(gridname,id) {
ColdFusion.navigate('newseditor.cfm?action=update&ID='+id,'CentralAdmin');
</script>
And
<cfajaxproxy bind="javascript:UpdateFromGrid('SearchResults',{SearchResults.id})">
<cfajaxproxy bind="javascript:UpdateFromGrid('LastNews',{LastNews.id})">
Where SearchResults and LastNews are the two cfgrids and CentralAdmin is the cflayout.
But I had the problem of selecting the previous selected row, arised by Peter. This is a problem in particular if your search query returns just one row. You can click on it just once. This other great article by Raymond (http://www.coldfusionjedi.com/index.cfm/2007/8/20/...) suggested my the solution:
<script>
function UpdateFromGrid(gridname,id) {
ColdFusion.navigate('newseditor.cfm?action=update&ID='+id,'CentralAdmin');
mygrid = ColdFusion.Grid.getGridObject(gridname);
sm = mygrid.getSelectionModel()
sm.clearSelections(false);
</script>
Unfortunately this didn't work. The selection was cleared but the onChange event was still not fired when selecting again a previously selected row.
Studying cfgrid.js I think to have finally find the solution:
<script>
function UpdateFromGrid(gridname,id) {
ColdFusion.navigate('newseditor.cfm?action=update&ID='+id,'CentralAdmin');
mygrid = ColdFusion.Grid.getGridObject(gridname);
sm = mygrid.getSelectionModel()
sm.clearSelections(false);
ColdFusion.objectCache[gridname].selectedRow=-1;
</script>
This worked for me. Now I have two different grid controlling a cflayout and you can click on previously clicked row and have the action fired.
Thanks so much for this very useful post. The CF 8 docs are very obtuse on this point; they make it seem like you can just use the cfgrid's onchange event listener. However, onchange doesn't seem to work in this context. Your post has saved the day after about 4-6 hours of searching.
Thanks!
-Neil
I have a fuseaction that sets up the cflayout. A default tab has another fuseaction as its source. This tab contains a cfgrid which when a row is click it fires the noteChange function which creates a new tab and uses another fuseaction as the source also passing the id in the source url.
How do I pick up that id within the new tab?
Here's the javascript:
<script>
noteChange = function(orderid) {
var newTab = 'odetail_' + orderid;
var newName = 'Order Details:- ' + orderid;
var oUrl = 'index.cfm?page=admin.orderDetail&orderid=' + orderid;
ColdFusion.Layout.createTab('tabcontainer',newTab,newName,oUrl,{closable:true});
ColdFusion.Layout.selectTab('tabcontainer',newTab);
}
</script>
Also, notice that I had to define the function as noteChange = function() {}
rather than just function noteChange() {}
I read in the docs that this is something to do with the fact that the script is running from within a tab rather than the top level page.
bind="cfc:employeeService.getData({cfgridpage},{cfgridpagesize},
{cfgridsortcolumn},{cfgridsortdirection},{grid1.FirstName})"
i just don't know whats getting passed in {grid1.FirstName} the first time page loads. The grid is always blank on page load. Only when a row is clicked, results are filtered in grid2.
I've been scratching my head for hours..unable to find whats wrong..pls help someone..


Thanks to your help I have got some pretty cool grids working by binding to a cfdiv.
Here is a little demo of one.
http://demo.thinksys.com/cf8/cfgrid/contacts.cfm
Thanks again for all the help.