Many people have asked how they can add custom toolbars to their grid components. In Ext 2.0 they are built in to the grid panel but in 1.1 they are built in to the grid view. It is the same concept but just tackled a little different. As we all know ColdFusion 8 ships with 1.1 so we will focus on that version. So why the need for custom toolbars? Well our example makes a case for both a header and footer toolbar. We will use the header to provide some nice buttons for adding and deleting records and our footer is a nice place for a status bar.
If you have been following my grid examples lately some of this will look familiar. I will be using the cfartgallery data source that ships with ColdFusion 8. The first thing we need to do is write a query to grab some data from our artists table. Next we setup some grid attributes and pass them in using attribute collection. Finally we are going to call a method called init when the page loads using the ajaxOnLoad tag.
ColdFISH is developed by Jason Delmore. Source code and license information available at coldfish.riaforge.org
<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")>
1<cfquery name="getArtists" datasource="cfartgallery">
2SELECT artistId, firstname, lastname, address, city, state, postalcode, email
3FROM Artists
4</cfquery>
5
6<cfset args = structNew()>
7<cfset args.name = "ArtistGrid">
8<cfset args.format = "html">
9<cfset args.query = "getArtists">
10<cfset args.stripeRows = true>
11<cfset args.selectColor = "##D9E8FB">
12
13<cfform>
14 <cfgrid attributeCollection="#args#">
15 <cfgridcolumn name="artistid" display="false">
16 <cfgridcolumn name="firstname" header="First Name">
17 <cfgridcolumn name="lastname" header="Last Name">
18 <cfgridcolumn name="email" header="Email Address">
19 <cfgridcolumn name="address" header="Address">
20 <cfgridcolumn name="city" header="City">
21 <cfgridcolumn name="state" header="State">
22 <cfgridcolumn name="postalcode" header="Zip">
23 </cfgrid>
24</cfform>
25
26<cfset ajaxOnLoad("init")>
In our init method we first need to get the grid object and can do so by using the ColdFusion.Grid.getGridObject method. This method is looking for the name of your grid. Remember that this is case sensitive so make sure you provide exact name that you used as the grids name. Now that we have the grid we can call the getView() method which return the grids view. If you look in the documentation the GridView Class has 2 methods we are interested in; getHeaderPanel() & getFooterPanel. These methods will basically get you a panel in the header or footer of the grid that can be used for toolbars etc.
ColdFISH is developed by Jason Delmore. Source code and license information available at coldfish.riaforge.org
<script type="text/javascript">
function init(){
grid = ColdFusion.Grid.getGridObject("ArtistGrid");
var gridFoot = grid.getView().getFooterPanel(true);
var gridHead = grid.getView().getHeaderPanel(true);
}
</script>
1<script type="text/javascript">
2 function init(){
3 grid = ColdFusion.Grid.getGridObject("ArtistGrid");
4 var gridFoot = grid.getView().getFooterPanel(true);
5 var gridHead = grid.getView().getHeaderPanel(true);
6 }
7 </script>
Now that we have our our header and footer panels we need to create some toolbars to add to them. To do this we need to import the classes used by Ext to create toolbars.
ColdFISH is developed by Jason Delmore. Source code and license information available at coldfish.riaforge.org
<script type="text/javascript" src="/CFIDE/scripts/ajax/ext/package/toolbar/toolbar.js"></script>
1<script type="text/javascript" src="/CFIDE/scripts/ajax/ext/package/toolbar/toolbar.js"></script>
Now we are ready to make some toolbars. If you not sure how toolbars work or the properties / methods available to them I suggest you check out the documentation.
ColdFISH is developed by Jason Delmore. Source code and license information available at coldfish.riaforge.org
var bbar = new Ext.Toolbar(gridFoot);
var tbar = new Ext.Toolbar(gridHead);
1var bbar = new Ext.Toolbar(gridFoot);
2var tbar = new Ext.Toolbar(gridHead);
Now I can start adding items to my toolbar. In the footer toolbar I am going to add a text item that will display the number of records used by the grids datasource. In the header I am going to add a couple of buttons that mix text and icons. You will notice for that each button their is a handler attribute. This is the method that will be called when the buttons click event is activated.
ColdFISH is developed by Jason Delmore. Source code and license information available at coldfish.riaforge.org
bbar.add(new Ext.Toolbar.TextItem('Total Artists: ' + grid.getDataSource().totalLength));
tbar.addButton({
text:"Add New Artist",
cls:"x-btn-text-icon",
icon:"add.png",
handler:onAdd
});
tbar.addSeparator()
tbar.addButton({
text:"Delete Artist",
cls:"x-btn-text-icon",
icon:"delete.png",
handler:onDelete
});
1bbar.add(new Ext.Toolbar.TextItem('Total Artists: ' + grid.getDataSource().totalLength));
2
3 tbar.addButton({
4 text:"Add New Artist",
5 cls:"x-btn-text-icon",
6 icon:"add.png",
7 handler:onAdd
8 });
9 tbar.addSeparator()
10 tbar.addButton({
11 text:"Delete Artist",
12 cls:"x-btn-text-icon",
13 icon:"delete.png",
14 handler:onDelete
15 });
Now we can add our button methods. These methods do not do much right now but you see how easy it would be to add some real functionality.
ColdFISH is developed by Jason Delmore. Source code and license information available at coldfish.riaforge.org
function onAdd(button,event){
alert("Row Added");
}
function onDelete(){
var grid = ColdFusion.Grid.getGridObject("ArtistGrid");
var record = grid.getSelections();
alert("Artist " + record[0].data.FIRSTNAME + " " + record[0].data.LASTNAME + " deleted");
}
1function onAdd(button,event){
2 alert("Row Added");
3 }
4 function onDelete(){
5 var grid = ColdFusion.Grid.getGridObject("ArtistGrid");
6 var record = grid.getSelections();
7 alert("Artist " + record[0].data.FIRSTNAME + " " + record[0].data.LASTNAME + " deleted");
8 }
That is really all there is to it. Customizing the AJAX Components that ship with ColdFusion are easy. All you need to do is dig into the Ext documentation and find out what is available to you. As always please leave me any questions / comments.
Example Source Code
ColdFISH is developed by Jason Delmore. Source code and license information available at coldfish.riaforge.org
<html>
<head>
<title>Custom Toolbars Example</title>
<script type="text/javascript" src="/CFIDE/scripts/ajax/ext/package/toolbar/toolbar.js"></script>
<script type="text/javascript">
function init(){
grid = ColdFusion.Grid.getGridObject("ArtistGrid");
var gridFoot = grid.getView().getFooterPanel(true);
var gridHead = grid.getView().getHeaderPanel(true);
var bbar = new Ext.Toolbar(gridFoot);
var tbar = new Ext.Toolbar(gridHead);
bbar.add(new Ext.Toolbar.TextItem('Total Artists: ' + grid.getDataSource().totalLength));
tbar.addButton({
text:"Add New Artist",
cls:"x-btn-text-icon",
icon:"add.png",
handler:onAdd
});
tbar.addSeparator()
tbar.addButton({
text:"Delete Artist",
cls:"x-btn-text-icon",
icon:"delete.png",
handler:onDelete
});
console.log(tbar);
console.log(bbar);
}
function onAdd(button,event){
alert("Row Added");
console.log(button);
console.log(event);
}
function onDelete(){
var grid = ColdFusion.Grid.getGridObject("ArtistGrid");
var record = grid.getSelections();
alert("Artist " + record[0].data.FIRSTNAME + " " + record[0].data.LASTNAME + " deleted");
}
</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>
1<html>
2<head>
3 <title>Custom Toolbars Example</title>
4
5 <script type="text/javascript" src="/CFIDE/scripts/ajax/ext/package/toolbar/toolbar.js"></script>
6
7 <script type="text/javascript">
8 function init(){
9 grid = ColdFusion.Grid.getGridObject("ArtistGrid");
10 var gridFoot = grid.getView().getFooterPanel(true);
11 var gridHead = grid.getView().getHeaderPanel(true);
12
13 var bbar = new Ext.Toolbar(gridFoot);
14 var tbar = new Ext.Toolbar(gridHead);
15
16 bbar.add(new Ext.Toolbar.TextItem('Total Artists: ' + grid.getDataSource().totalLength));
17
18 tbar.addButton({
19 text:"Add New Artist",
20 cls:"x-btn-text-icon",
21 icon:"add.png",
22 handler:onAdd
23 });
24 tbar.addSeparator()
25 tbar.addButton({
26 text:"Delete Artist",
27 cls:"x-btn-text-icon",
28 icon:"delete.png",
29 handler:onDelete
30 });
31
32 console.log(tbar);
33 console.log(bbar);
34
35 }
36
37 function onAdd(button,event){
38 alert("Row Added");
39
40 console.log(button);
41 console.log(event);
42 }
43 function onDelete(){
44 var grid = ColdFusion.Grid.getGridObject("ArtistGrid");
45 var record = grid.getSelections();
46 alert("Artist " + record[0].data.FIRSTNAME + " " + record[0].data.LASTNAME + " deleted");
47 }
48 </script>
49</head>
50<body>
51
52<cfquery name="getArtists" datasource="cfartgallery">
53SELECT artistId, firstname, lastname, address, city, state, postalcode, email
54FROM Artists
55</cfquery>
56
57<cfset args = structNew()>
58<cfset args.name = "ArtistGrid">
59<cfset args.format = "html">
60<cfset args.query = "getArtists">
61<cfset args.stripeRows = true>
62<cfset args.selectColor = "##D9E8FB">
63
64<cfform>
65 <cfgrid attributeCollection="#args#">
66 <cfgridcolumn name="artistid" display="false">
67 <cfgridcolumn name="firstname" header="First Name">
68 <cfgridcolumn name="lastname" header="Last Name">
69 <cfgridcolumn name="email" header="Email Address">
70 <cfgridcolumn name="address" header="Address">
71 <cfgridcolumn name="city" header="City">
72 <cfgridcolumn name="state" header="State">
73 <cfgridcolumn name="postalcode" header="Zip">
74 </cfgrid>
75</cfform>
76
77<cfset ajaxOnLoad("init")>
78
79
80
81 <cfsavecontent variable="head">
82 <link href="/CFIDE/scripts/ajax/ext/resources/css/ytheme-aero.css" rel="stylesheet" type="text/css">
83 <link href="/CFIDE/scripts/ajax/ext/resources/css/menu.css" type="text/css" rel="stylesheet"/>
84 </cfsavecontent>
85
86 <cfhtmlhead text="#head#">
87
88</body>
89</html>
This entry was posted on March 5, 2008 at 10:19 AM and has received 14583 views. Comments 37 |
Print this entry.
#1 by Mike on 3/5/08 - 3:31 PM
The example works great except that the images don't show. Where do the .png files need to be located? I do not have add.png or delete.png anyhwere in my /CFIDE. I have .gif versions, but I cannot get those to display either.
Thanks!
Mike
#2 by Dan Vega on 3/5/08 - 3:34 PM
#3 by Mike on 3/5/08 - 4:57 PM
#4 by Dan Vega on 3/5/08 - 5:00 PM
#5 by Trond Ulseth on 3/6/08 - 10:00 AM
#6 by Mosey on 4/8/08 - 12:33 PM
That is add button is nice for the alert but I want it to actually call a cfc function that deletes.
#7 by Rachael on 4/12/08 - 12:13 AM
if i put all those codes in the wwwroot under some folder, it worked fine.
when i put all those codes in wwwroot under Project -> Apps -> Monitor. it gets weird. ajaxOnLoad doesnt seem to be working. I get no buttons..
I'm stumped on this thing for whole day.
#8 by Glyn on 4/16/08 - 12:38 PM
thanks
#9 by Dan Vega on 4/17/08 - 9:23 AM
@Glyn - I am not sure I understand what you are trying to do. The buttons are creating and they are each given a click handler. This means call this method when I am cliked. Once the action is transfered to that method it is up to you supply the implementation.
#10 by Glyn on 4/17/08 - 10:03 AM
<cffunction name="editProductOptions" 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]>
</cfcase>
<!--- Process deletes --->
<cfcase value="D">
<!--- Perform actual delete --->
<cfquery datasource="#dbSource#" username="#dbUsername#" password="#dbPassword#">
DELETE FROM product
WHERE productOptionId = #ARGUMENTS.gridrow.productOptionId#
</cfquery>
</cfcase>
</cfswitch>
</cffunction>
#11 by Dan Vega on 4/17/08 - 10:07 AM
#12 by Glyn on 4/17/08 - 10:12 AM
<cfgrid name="AllOptionForProduct"
format="html"
pagesize="15"
striperows="yes"
selectmode="edit"
delete="yes"
deletebutton="Delete this Option"
width="auto"
height="495"
bind="cfc:salesmaxx3.components.grids.getProdOption({cfgridpage},
{cfgridpagesize},
{cfgridsortcolumn},
{cfgridsortdirection}, #url.prodid#)"
onchange="cfc:salesmaxx3.components.grids.editProductOptions({cfgridaction},
{cfgridrow},
{cfgridchanged})">
<cfgridcolumn name="productOptionId" header="value" display="no" />
<cfgridcolumn name="value" header="value" width="200" />
<cfgridcolumn name="optionprice" header="Price" width="200" />
</cfgrid>
#13 by Glyn on 4/17/08 - 10:15 AM
#14 by Cliff on 4/18/08 - 10:17 AM
I can't seem to get the buttons to add to the header bar. I'm using HostMySite.com and they are notorious for access restrictions so that might be the case. Here is my code:
<script type="text/javascript" src="/CFIDE/scripts/ajax/ext/package/toolbar/toolbar.js"></script>
<script type="text/javascript">
function init(){
grid = ColdFusion.Grid.getGridObject("grdSubCategory");
var gridHead = grid.getView().getHeaderPanel(true);
var tbar = new Ext.Toolbar(gridHead);
tbar.add(new Ext.Toolbar.TextItem('Total Records: ' + grid.getDataSource().totalLength));
tbar.addSeparator();
tbar.addButton({text:"Add New", handler:onAdd });
tbar.addSeparator();
tbar.addButton({ text:"Delete", handler:onDelete });
}
</script>
Here is a link to the image of what this produces:
http://www.lmelectronics.com/images/gridResults.jp...
#15 by Dan Vega on 4/18/08 - 10:19 AM
#16 by Cliff on 4/18/08 - 11:04 AM
I added the following:
------------------
function onAdd(){}
function onDelete(){
var grid = ColdFusion.Grid.getGridObject("grdSubCategory");
var record = grid.getSelections();
alert("Record " + record[0].data.SC_NAME + " deleted. Total Length:" +grid.getDataSource().totalLength);
}
------------------
I'll add something in them in a bit but actually adding them in the <script> was the problem there.
This part of the code still returns "undefined" in the top bar though:
tbar.add(new Ext.Toolbar.TextItem('Total Records: ' + grid.getDataSource().totalLength));
Using the onDelete button I added an alert to tell me the value of:
grid.getDataSource().totalLength
It comes back just fine. Why would this not work in the top bar and work just fine in an alert box?
#17 by Dan Vega on 4/18/08 - 11:11 AM
I am not sure about the other problem. It works fine for me in the bottom bar. I would start logging some of that info to firebug to see what I come up with.
#18 by Cliff on 4/18/08 - 11:37 AM
console.log(grid.getDataSource());
console.log("total length: " + grid.getDataSource().totalLength);
When you drill down in the first entry there is a totalLength and it is listed as 1.
The second entry is listed as "undefined"
When I press the delete button I have it log the following:
console.log("total length: " + grid.getDataSource().totalLength);
It shows up as 1.
This is very strange, what am I missing?
#19 by Dan Vega on 4/18/08 - 2:14 PM
bbar.add(new Ext.Toolbar.TextItem('Total Artists: ' + grid.getDataSource().totalLength));
If you change it to tbar it works fine.
#20 by Matt on 6/2/08 - 12:08 PM
Unlike your example above, my query is in a CFC and I'm using the bind parameter for CFGRID, and bindonload defaults to yes. I think that when the page loads, the grid bind loads and anything called in InitGrid fires. Is there any way around this?
Thanks!
#21 by Dan Vega on 6/5/08 - 10:46 AM
So are you saying that you have created a cfwindow using tag syntax? Have you considered creating the window using JavaScript? I would have to see more code to understand your problem but I think I understand you right.
#22 by Jason on 6/10/08 - 5:06 PM
#23 by Dan Vega on 6/11/08 - 8:36 PM
console.log() is a way to trace information to Firebug. If you are running in IE either comment out remove any console.log() lines.
#24 by Glyn on 6/20/08 - 6:05 AM
record[0].data.firstname
the answer was it HAS to be in uppercase i.e.
record[0].data.FIRSTNAME
is there a reason for this i don't understand?
#25 by Michael Skinner on 7/10/08 - 12:08 PM
{
grid = ColdFusion.Grid.getGridObject("pod3");
var gridHead = grid.getView().getHeaderPanel(true);
var tbar = new Ext.Toolbar(gridHead);
alert('');
tbar.add(new Ext.Toolbar.TextItem('Total Records: ' + grid.getDataSource().totalLength));
tbar.addButton({text: 'Add',icon:'/oxford_portal/images/table_gear.png',cls: 'x-btn-text-icon', tooltip: 'Add a new user', handler: CreateWin_pod3} );
tbar.addButton({text: 'Delete',icon:'/oxford_portal/images/table_gear.png',cls: 'x-btn-text-icon', tooltip: 'Delete this user', handler: onDelete_pod3} );
}
Not sure what is goung on there
#26 by Calvert Acklin on 8/18/08 - 6:10 PM
Have you or anyone else figured out how to disable/enable a toolbar button? The API has a setDisabled() and disable() function, but they don't seem to work.
For example:
function onAdd(button,event){
alert("Row Added");
//false = enabled; true = disabled
Ext.getCmp("btnDelete").setDisabled(false); //Doesn't work
//Ext.getCmp("btnDelete").disable(); //Doesn't work
console.log(button);
console.log(event);
}
#27 by Calvert Acklin on 8/19/08 - 12:39 AM
addArtistButton = bbar.addButton({text:"Add Artist", handler:onAdd });
bbar.addSeparator();
deleteArtistButton = bbar.addButton({ text:"Delete Artist", handler:onDelete });
bbar.addSeparator();
disableDeleteArtistButton = bbar.addButton({ text:"Disable Delete", handler:onDisable });
bbar.addSeparator();
enableDeleteArtistButton = bbar.addButton({ text:"Enable Delete", handler:onEnable });
function onDisable(){
deleteArtistButton.setDisabled(true);
}
function onEnable(){
deleteArtistButton.setDisabled(false);
}
function onAdd(button,event){
ColdFusion.Window.show('addArtistWin');
}
function onDelete(){
ColdFusion.Window.show('deleteArtistWin');
}
#28 by Dan Vega on 8/26/08 - 10:00 AM
button.enabled = false;
#29 by Jose Alfonso on 8/29/08 - 9:03 PM
It's all very useful but with all the hacking going on and the very obvious differences between what CF uses of Ext and v2.2. Did you not find yourself choosing to use the newer library instead of the CF related tags?
By the way, a constructive criticism: Information specific about your cfext seems scattered and mixed in with your CF hacks here in the blog. You are such a mentor in several subjects that you seem to have outgrown this "blog format".
I think some of you guys can benefit from a format similar to the ext 2.2 docs (is that awesome or what!)
#30 by Calvert Acklin on 9/28/08 - 12:41 AM
I know the grid can be set to multiselect mode via the following:
// enable multiSelect within Grid Object
ColdFusion.Grid.getGridObject('ArtistGrid').getSelectionModel().singleSelect = false;
But am wondering if you or anyone else knows how to delete the selected Artists.
#31 by Calvert Acklin on 9/29/08 - 9:22 AM
var grid = ColdFusion.Grid.getGridObject('Artist');
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("ARTISTID");
//use join() to convert array to a string
str = arrSelTemp.join();
Ext.Msg.alert("Show selections: ","Select: " + str);
};
#32 by knk on 10/17/08 - 9:57 AM
for example <cfset args.pagesize = "10">
How should I go about this?
Thanks
#33 by Dan Vega on 10/17/08 - 10:03 AM
#34 by Chris Ulrich on 9/30/09 - 3:40 PM
The buttons base used (by me) to open CFWINDOWs. The <cfset ajaxOnLoad("init")> was not being invoked at the bottom of the page. For the heck of it, I moved it above the CFWINDOW statements and boom - it all worked fine.
So, for what its worth, for anyone having trouble getting buttons to show up, try nudging that <cfset ajaxOnLoad("init")> statement higher on the page. It just might do the trick. :^)
#35 by David on 10/15/09 - 11:19 AM
grid = ColdFusion.Grid.getGridObject("ArtistGrid");
var gridFoot = grid.getView().getFooterPanel(true);
var gridHead = grid.getView().getHeaderPanel(true);
I just get an errorError: grid.getView().getHeaderPanel is not a function
#36 by Tim on 12/30/09 - 11:08 AM
For this to work under CF9, see:
http://www.coldfusionjedi.com/index.cfm/2009/10/15...
#37 by Brett on 4/19/11 - 1:57 PM