Filtering Records In An Ajax Grid

Posted By : todd sharp Posted At : August 9, 2007 12:20 PM Posted In: Ajax, ColdFusion

38

The first thought that comes to my mind when working with grids is 'how can I filter/search within the results?' Grids are very nice - especially the new Ajax grid in ColdFusion 8. But they can be a bit difficult to quickly get at something that you may know exists. Here is one method to do filtering.

I've chosen to highlight this method on purpose - there is another method that may be a bit simpler but I wanted to highlight something cool with this method. It is also possibly a preferable method when dealing with grids that have many pages of data and are a little less responsive the others because it does not filter the results as you type. So on to the code:

The first chunk I'll show is the grid and the search box and search button. In the grid I am using a bind statement that calls my 'art' CFC. The CFC follows the necessary format for working with grids (for more on that see the developers guide).

<cfinput name="searchString" />
<cfinput type="button" name="searchBtn" value="Search" onclick="ColdFusion.Grid.refresh('artGrid', false);" />
<cfgrid
    format="html"
    name="artGrid"
    pagesize="5"
    sort="true"
    bind="cfc:art.getArt({cfgridpage},{cfgridpagesize},{cfgridsortcolumn},{cfgridsortdirection}, getSearchString())">

    
    <cfgridcolumn name="artid" header="ID" />
    <cfgridcolumn name="artname" header="Name" />
    
</cfgrid>

The first four arguments that I'm passing are needed to do the dynamic paging. The thing that is cool about this bind statement is the fifth argument - getSearchString() - which is not a form field value but a JavaScript function that looks like this:

<script>
getSearchString = function(){
    var s = ColdFusion.getElementValue('searchString');
    return s;
}
</script>

Can't get much simpler then that really. This function gets the current value of the cfinput 'searchString' and returns it. So on load of the page this will normally be blank - which passes an empty string to the CFC (the query in my CFC will only limit the results if the search string exists).

So how does the search happen? Well it won't happen when I type in the cfinput because I'm not binding directly to that control. I handle the refresh in the onClick of the search button (you could also make it a submit button and handle the refresh onSubmit of the form so that a simple press of the enter key will do the search).

onclick="ColdFusion.Grid.refresh('artGrid', false);"

So here I refresh the artGrid. At this point the bind statement is reevaluated and the getSearchString function will now return the searchString and the CFC can limit the results.

Here is an online demo.

Comments (38)

Abul's Gravatar Nice example.. Is there a possible way to open up cfwindow while I click on data grid filed -- which will open up cfwindow related to clicked content?

Thanks.

todd sharp's Gravatar Absolutely. You could bind to the grid in the source attribute of your cfwindow. The window could then access that dynamic variable (like a primary key) to get details.

todd sharp's Gravatar I should mention - if you wanted the window to automatically fire when the grid row is selected you'll have to tap into the underlying Ext grid object and register a listener.

todd sharp's Gravatar Or use cfajaxproxy :)

But now that I think of it - it would probably be pretty annoying to open a window everytime you select a different row in the grid.

Keith Korry's Gravatar I need to know how to make my own application and database page the results. Do you have an example of this?

todd sharp's Gravatar Not sure I follow your question Keith - can you explain a little more what you're trying to do?

todd sharp's Gravatar Abul - check Ray's post for an example of reacting to a grid row selection change:

http://www.coldfusionjedi.com/index.cfm/2007/8/9/R...

Abul's Gravatar Excellent help. Whenever you come to Houston -- I will buy you a launch!

:) Abul

Abul's Gravatar Typo :{

Should be "lunch"

Abul

Dave Ferguson's Gravatar Great example. I have a question though. What if you want to have not only a searchstring but the value from, lets say, a dropdown? It it possible to get both of those values inside if the single getSearchString() function? I tried playing around with this and came up with nothing but making multiple functions.

--Dave

todd sharp's Gravatar How about this Dave:

getSearchString = function(){
   var s = {};
   s.string = ColdFusion.getElementValue('searchString');
   s.col = ColdFusion.getElementValue('searchCol');
   return s;
}

This will pass a struct in the 5th position - and can be handled accordingly. :)

Dave Ferguson's Gravatar Ok now I feel stupid. I should have been able to figure that out. Thanks todd.

--Dave

todd sharp's Gravatar Nah no worries - it isn't immediately obvious in my opinion. You happened to catch me at an alert moment - normally I would have fumbled with that for an hour before I figured out it was that easy ;)

Cyrill's Gravatar Todd, Is there a way to capture a URL variable and pass it as well?

For example if I have a cfmenu that points to a separate page of listings by category (want to keep a separate url for SEO reasons). I am very new to this ajax thing but have been inhaling it from all of the blogs recently.

todd sharp's Gravatar technically you could just set the value of the cfinput to the url var. something like this:

<cfinput name="searchString" value="#url.foo#" />

That should initally filter based on the url far foo - is that what you meant?

Keith Korry's Gravatar How do you tell the flash form to page a certain amount of records.
Page 1
Page 2

Like 10 per page...

todd sharp's Gravatar Flash forms are a whole different topic Keith. This demo is for the ColdFusion 8 Ajax grid. There is nothing built in for the flash grid for paging.

Cyrill's Gravatar Todd,

Thank you so much. The hidden field with a URL parameter worked perfectly.

Now, is there a way to bind different columns to different functions in a CFC, for example: selecting (clicking) one column loads company data, clicking on a city name in the CITY column displays only entries from that city? I looked at Ray's blog but it looks like his use of the cfajaxproxy selects the whole row.

Keith Korry's Gravatar I mean coldfusion (flash) grid.
If I make a grid from a sql db connection and I want only 10 per page How do I make it show only 10.

Keith Korry's Gravatar CFGRID- Pagesize The number of rows to display per page for a dynamic grid. If the number of available rows exceeds the page size, the grid displays only the specified number of entries on a single page, and the user navigates between pages to show all data. The grid retrieves data for each page only when it is required for display.

This attribute is ignored if you specify a query attribute.

Keith Korry's Gravatar Nope Still Doesnt Work, Heres the code...
<cfquery name="R1" datasource="canadadb" maxrows="200">
SELECT *
FROM dbo.cities
</cfquery>
<cfform>
<cfgrid query="R1"
name="R1"
format="html"
pagesize="10"
striperows="yes">
<cfgridcolumn name="id" header="First Name"/>
<cfgridcolumn name="weather" header="weather"/>
<cfgridcolumn name="cities" header="cities"/>
<cfgridcolumn name="province" header="province"/>
</cfgrid>
</cfform>

Marty McGee's Gravatar Hey Todd,

Great website!! It's always the first I go to in the morning. Keep up the genius (and very helpful) work.

I'm still getting my head around cf8's new bind stuff, and I was wondering if you could post your getArt.cfc contents for us to have a looksee? I'm getting a coldfusion error:

You cannot specify more arguments to a CFC function than it declares.
---- Error parsing bind cfc:customers.getData({cfgridpage},{cfgridpagesize},{cfgridsortcolumn},{cfgridsortdirection}, getSearchString()) ----

Thanks again for all you do for us cfJunkies.

Ray Buechler's Gravatar Todd,

I will second Marty's request for the art.cfc. I figured out that you need a getSearchString argument in the cfc or else you get the error Marty mentions but the filtering does not work. No error but the dataset does not get filtered.

Thanks for providing this example. I very much appreciate it!

todd sharp's Gravatar Marty: Sorry! Did not see your request earlier...

For those who are interested the cfc is now an attachment to this blog post. Download above.

HTH.

Howie's Gravatar How would you enhance this to filter the grid as you type and remove the submit button?

todd sharp's Gravatar Just add an onchange to the text input that does the same thing as the button. But I'd strongly suggest not doing that since that would mean every character entered would fire off an Ajax request and that could get messy/laggy real quick.

sneha's Gravatar Hi i need some help with this:
I have two grids (grid1 & grid2). I want grid2 results to be filtered based on grid1 selection (which i was able to do) but initially on page load i want all records to show up on grid2.
This is what i have:
function init(){
//window.filterParam = '';
grid = ColdFusion.Grid.getGridObject("grid1");
grid.addListener("rowclick",setValue);
}
function setValue()
{
//window.filterParam = '';
var grid = ColdFusion.Grid.getGridObject("grid1");
var record = grid.getSelections();
window.filterParam = record[0].data.FIRSTNAME;

var grid2 = ColdFusion.Grid.getGridObject("grid2");
grid2.refresh();
}
function getValue()
{
return window.filterParam;
}

And the bind attribute for grid2 has:
<cfgrid format="html" name="employeeGrid"
bind="cfc:employeeService.getData({cfgridpage},{cfgridpagesize},
   {cfgridsortcolumn},{cfgridsortdirection},getValue())"

Whats happening is, on page load all records display on grid2. But when a row from grid1 is clicked, still grid2 shows all records. Only when a second row from grid1 is clicked, results pertaining to previous grid1 selection (not current selection) get filtered in grid2.

I printed 'window.filterParam' when every grid1 row is clicked and it seems to be getting the right value, but for some reason grid2 results aren't getting refreshed.

please someone help!!

Aaron's Gravatar Hi there,

I am a bit of a noob to this. In your example iof passing more than one search param:

getSearchString = function(){
var s = {};
s.string = ColdFusion.getElementValue('searchString');
s.col = ColdFusion.getElementValue('searchCol');
return s;
}

Can you PLEASE tell me how I would reference this in my CFC and query??? And in the bind statement of the grid do you still use getSearchString() to pass the structure.

THANK YOU.

sneha's Gravatar Nevermind. It seemed like flawed idea. So didn't pursue it.

Ved's Gravatar Hi,

Im using some exact similar code to load 300 or so records from my DB to the GRID across 4 or 5 pages is pagesize.


This takes about 2-3 minutes for the initial Load & 100% of my CPU !!!

The same data when loaded into a CFGRID- format=APPLET runs in 20 seconds or less.

The Sql table that i extract the data into a CFC is only about 2000 rows in size & the query runs in less than 20 millisecs.

Can someone explain what am i missing ?

Thanks

futr_vision's Gravatar I'm trying to do something similar to this. I have a 9 column grid with 4 columns that need to be searchable/filterable. One column will contain a unique value much like your grid and benefit from a text field search. The other three have consistent/predictable values and could be filtered using a dropdown box however I would also like them available for the text search. I simply have no idea where to start.

As an added bonus question I have seen search text fields that filter the data as you type. How can that be done?

mana's Gravatar Hi, Thanks for your solution it works perfect in IE 7, the only problem I have is, Grid is not load in IE 8 or higher , only it works when I push the Compatibility button on the top, Also it’s not working in the Firefox or safari. Any suggestion for that?

Thanks,

Alex Gutierrez's Gravatar Hi Todd, I like you demo.. I am trying to pass multiple search strings but i keep getting and error.

I am using this approach:
getSearchString = function(){
var s = {};
s.string = ColdFusion.getElementValue('searchString');
s.col = ColdFusion.getElementValue('searchCol');
return s;
}

how would i pull the values from the struct in my cfc.. i keep getting a empty grid and the in fire bug i see that the values are being passed.

thanks

Sandra's Gravatar How can I prevent the cfselect from calling the CFC? Even though we're NOT using onchange in the cfselect, every time the users select a new value in the cfselect the CFC is called and the grid refreshes. Is there any way that this only happens when the user only clicks on the button?

<cfselect id="column" name="column" >
<option value=""></option>
<option value="ID">Ticket Number</option>
<option value="PO">PO Number</option>
</cfselect>
<cfinput name="searchString" />
<cfinput type="button" name="searchBtn" value="Search" onclick="ColdFusion.Grid.refresh('files',false)" />

Josh's Gravatar same question as a couple other folks, trying to pass a string and a column value and don't know how to handle it on the CFC side. Any way you can post a quick modification of your getArt method to demonstrate how to do handle the passed in struct?

BrotherSun's Gravatar I'd like to extend CFGRID to include links which, when clicked would move the row up or down. Step 1 (done):
I've added two additional columns to the query that drives my CFGRID like so:

SELECT *, '<a href=javascript:alert(''call_function_to_move_row_up'') title="Move this row up">Up</a>' AS Up,
'<a href=javascript:alert(''call_function_to_move_row_up'') title="Move this row down">Down</a>' AS Down

Step 2: Write the javascript functions to swap the rows based on a sort column, save the grid data and refresh.

Just curious if anyone has done this aready, or seen it done somewhere. Thanks in advance for any tips!

Marc's Gravatar Hi,

I've copied the 2 files and makes the change to fit with my environnement.
When i launch the page, i've no error message, the grid appear but empty.

What am i doing wrong please ?

Regards

Marc

Mitchell's Gravatar Is this method suite for Coldfusion 9 cfgrid.
I have tried it on CF 9 cfgrid, but it did not work. I do not know why? l like cfgrid pageing function, but I can found any method to send the 5th argument (or more) to it. Once I though I found the answer on your post, but I feel I would go find more inform, now. actually speaking, for a CF beginner this requirement should be basic and have to configure it out, but should say, it is not easy.........