Over the past couple of weeks I have been writing quick tutorials on extending the built in AJAX components. Today I would like to show you an example that I believe everyone is going to find useful. Once you have a data grid displaying your data there are usually 2 key operations users will perform. The 1st is pagination of records which is built into the grid and is pretty easy to use. The 2nd is filtering or how can I find exactly what I am looking for without browsing all of the records. Most filter examples I have seen where built outside of the grid but I want to run through an example that builds a filter into the grid.

Before we get started I think we should take a look at the outcome, this way the tutorial makes a little more sense. I do not have 8 running so I will have to explain this using pictures. First we have a list of artists and I provide the user a way to filter the artists by what state they are in. When the state is selected the grid is updated.

This demo like the others uses the cfartgallery data source that ships with CF so you should be able to run this example without any setup. The first thing we need to do is run our query and display our grid. This is pretty basic and you should understand what is going on here.

view plain print about
1<cfquery name="getArtists" datasource="cfartgallery">
2    SELECT artistId, firstname, lastname, address, city, state, postalcode, email
3    FROM 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    <cfset args.width = 600>
13    
14    <cfform>
15        <cfgrid attributeCollection="#args#">
16            <cfgridcolumn name="artistid" display="false">
17            <cfgridcolumn name="firstname" header="First Name">
18            <cfgridcolumn name="lastname" header="Last Name">
19            <cfgridcolumn name="email" header="Email Address">
20            <cfgridcolumn name="address" header="Address">
21            <cfgridcolumn name="city" header="City">
22            <cfgridcolumn name="state" header="State">
23            <cfgridcolumn name="postalcode" header="Zip">
24        </cfgrid>
25    </cfform>
Now that our grid is setup we need to call a function post setup. We can do this using the ajaxOnLoad tag.
view plain print about
1<cfset ajaxOnLoad("init")>
I am going to be using some toolbar and button code that is a part of the Ext framework. To make use of those classes we must import them.
view plain print about
1<script type="text/javascript" src="/CFIDE/scripts/ajax/ext/package/toolbar/toolbar.js"></script>    
2 <script type="text/javascript" src="/CFIDE/scripts/ajax/ext/package/button/button.js"></script>
Now that we setup our init method that will automatically get called after the page is setup. We need to get the grid component and we can use the built in method to do so. Next if you read my custom toolbar article you know the next couple of lines grabs the header panel and creates a toolbar on it.
view plain print about
1<script type="text/javascript">
2 function init(){
3        grid = ColdFusion.Grid.getGridObject("ArtistGrid");
4        var gridHead = grid.getView().getHeaderPanel(true);
5        var tbar = new Ext.Toolbar(gridHead);
6        
7 }
8
9 </script>
Now we need to build our combo box that will be used as a filter. If you are not familiar with Ext you may want to look at the docs. A Combo box can loaded using json but for this example to keep things simple I am just going to load the box inline. The empty text attribute the text to display in the box while now selection is made.
view plain print about
1cb = new Ext.form.ComboBox({
2     id:"stateFilter",
3     emptyText:"Filter By State",
4     mode:"local",
5     triggerAction:"all",
6     displayField:"text",
7     valueField:"value",
8            store:new Ext.data.SimpleStore({
9                fields: ["value", "text"],
10                data: [
11                    ["CA","California"],
12                    ["CO","Colorado"],
13                    ["FL","Florida"],
14                    ["GA","Georgia"],
15                    ["NY","New York"],
16                    ["SD","South Dakota"]
17                ]
18     })
19 });
Now that we have created our combo box we need to add an event listener. What we are saying is when a user selects something do the following. Using the grid reference we created at the top of the function we can grab the grids store (datasource) and use a built in method filter. The filter method takes two arguments, the column you want to filter on and the value you want to to filter.
view plain print about
1cb.addListener("select",function(combo,record,index){
2var state = record.data.value;
3 //filter the records
4 grid.getDataSource().filter("STATE",state);
5});
The filter is now setup, now we just need to add it to our toolbar. The first line ads a spacer in so that our toolbar items are right aligned. Next I add a button that can be used to remove the filter. After a state is selected this will give us a way to return back to the grids original state. We will look at the event handler for this button in a second. Then next we create a separator between our button and combo box and finally add our combo box.
view plain print about
1Ext.fly(tbar.addSpacer().getEl().parentNode).setStyle('width', '100%');
2 tbar.addButton({
3     text:"Remove Filter",
4         icon:"plugin.png",
5         cls:"x-btn-text-icon",
6         tooltip:"Remove Filter",
7         handler:removeFilter
8        });
9tbar.add(new Ext.Toolbar.Separator());
10tbar.add(cb);
Finally here is how the grids original state is restored. The store has a method for removing the filter and I simply reset the combo box the empty text is restored.
view plain print about
1function removeFilter(){
2        store = grid.getDataSource()
3        //remove the data filter
4        store.clearFilter();
5        //clear the value of the combo box
6        cb.clearValue();
7        //reset it so empty text shows up
8        cb.reset();
9    }

Hopefully this tutorial will show you that there is a great deal of customizing that can go into the grids. Hopefully this will inspire you to create your own filters. If you have any comments or questions just let me know. Plus I am looking for more ideas on extending the grid. If you have something you are trying to accomplish but not sure how just let me know. Here is the full code for the tutorial.

view plain print about
1<html>
2<head>
3 <title>Grid Filter Exmaple</title>
4
5 <script type="text/javascript" src="/CFIDE/scripts/ajax/ext/package/toolbar/toolbar.js"></script>    
6 <script type="text/javascript" src="/CFIDE/scripts/ajax/ext/package/button/button.js"></script>
7
8 <script type="text/javascript">
9 function init(){
10        grid = ColdFusion.Grid.getGridObject("ArtistGrid");
11        var gridHead = grid.getView().getHeaderPanel(true);
12        var tbar = new Ext.Toolbar(gridHead);
13        
14 cb = new Ext.form.ComboBox({
15     id:"stateFilter",
16     emptyText:"Filter By State",
17     mode:"local",
18     triggerAction:"all",
19     displayField:"text",
20     valueField:"value",
21            store:new Ext.data.SimpleStore({
22                fields: ["value", "text"],
23                data: [
24                    ["CA","California"],
25                    ["CO","Colorado"],
26                    ["FL","Florida"],
27                    ["GA","Georgia"],
28                    ["NY","New York"],
29                    ["SD","South Dakota"]
30                ]
31     })
32 });
33
34        cb.addListener("select",function(combo,record,index){
35            var state = record.data.value;
36            //filter the records
37            grid.getDataSource().filter("STATE",state);
38        });
39
40 Ext.fly(tbar.addSpacer().getEl().parentNode).setStyle('width', '100%');
41 tbar.addButton({
42     text:"Remove Filter",
43         icon:"plugin.png",
44         cls:"x-btn-text-icon",
45         tooltip:"Remove Filter",
46         handler:removeFilter
47        });
48        tbar.add(new Ext.Toolbar.Separator());
49        tbar.add(cb);
50        console.log(Ext);
51 }
52    function removeFilter(){
53        store = grid.getDataSource()
54        //remove the data filter
55        store.clearFilter();
56        //clear the value of the combo box
57        cb.clearValue();
58        //reset it so empty text shows up
59        cb.reset();
60    }
61 </script>
62</head>
63<body>
64    
65    <link href="/CFIDE/scripts/ajax/ext/resources/css/ytheme-aero.css" rel="stylesheet" type="text/css">
66    
67
68    <cfquery name="getArtists" datasource="cfartgallery">
69    SELECT artistId, firstname, lastname, address, city, state, postalcode, email
70    FROM Artists
71    </cfquery>
72    
73    <cfset args = structNew()>
74    <cfset args.name = "ArtistGrid">
75    <cfset args.format = "html">
76    <cfset args.query = "getArtists">
77    <cfset args.stripeRows = true>
78    <cfset args.selectColor = "##D9E8FB">
79    <cfset args.width = 600>
80    
81    <cfform>
82        <cfgrid attributeCollection="#args#">
83            <cfgridcolumn name="artistid" display="false">
84            <cfgridcolumn name="firstname" header="First Name">
85            <cfgridcolumn name="lastname" header="Last Name">
86            <cfgridcolumn name="email" header="Email Address">
87            <cfgridcolumn name="address" header="Address">
88            <cfgridcolumn name="city" header="City">
89            <cfgridcolumn name="state" header="State">
90            <cfgridcolumn name="postalcode" header="Zip">
91        </cfgrid>
92    </cfform>
93    
94    <cfset ajaxOnLoad("init")>
95
96</body>
97</html>