AG-Grid-React-Series #12: Filtering Data in AG Grid React
Welcome back to our AG Grid React series! In this twelfth installment, we're diving into a crucial feature for data exploration and analysis: **filtering data**. Filtering allows users to quickly narrow down large datasets to find specific information, making your AG Grid tables incredibly powerful and user-friendly. We'll cover various filtering mechanisms, from basic column filters to global quick filters, complete with practical React code examples.
By the end of this post, you'll be able to implement effective data filtering strategies in your AG Grid React applications, significantly enhancing the user experience.
Why Filtering is Essential
Imagine a table with thousands of rows. Without filtering, finding a specific entry or a group of related entries would be a daunting task. Filtering addresses this by:
- Improving Usability: Users can effortlessly locate relevant data.
- Enhancing Data Analysis: Isolate subsets of data for focused review.
- Increasing Productivity: Save time by reducing manual scanning.
Enabling Filtering in AG Grid React
The first step to utilize filtering is to enable it. You can do this globally for the entire grid or on a column-by-column basis.
Global Filtering: `enableFilters` Grid Property
To enable filtering for all columns that support it by default, set the enableFilters property to true in your gridOptions (or directly on the AgGridReact component).
import React, { useState, useRef, useCallback } from 'react';
import { AgGridReact } from 'ag-grid-react';
import 'ag-grid-community/styles/ag-grid.css';
import 'ag-grid-community/styles/ag-theme-alpine.css';
const MyFilteringGrid = () => {
const gridRef = useRef(null);
const [rowData] = useState([
{ make: "Toyota", model: "Celica", price: 35000, year: 2005 },
{ make: "Ford", model: "Mondeo", price: 32000, year: 2010 },
{ make: "Porsche", model: "Boxster", price: 72000, year: 2015 },
{ make: "BMW", model: "M3", price: 60000, year: 2018 },
{ make: "Audi", model: "A4", price: 45000, year: 2012 },
]);
const [columnDefs] = useState([
{ field: 'make' },
{ field: 'model' },
{ field: 'price' },
{ field: 'year' },
]);
return (
<div className="ag-theme-alpine" style={{ height: 400, width: 600 }}>
<AgGridReact
ref={gridRef}
rowData={rowData}
columnDefs={columnDefs}
enableFilters={true} // <-- Enable filtering globally
animateRows={true}
></AgGridReact>
</div>
);
};
export default MyFilteringGrid;
With enableFilters={true}, a filter icon will appear in the header of each column. Clicking this icon will reveal the default filter menu for that column type.
Column-Specific Filtering
While global enablement is convenient, you often need more control over how individual columns are filtered. AG Grid allows you to specify a filter type for each column using the filter property in its colDef.
1. Text Filter (`agTextColumnFilter`)
This is the default filter for string columns. It allows users to filter based on text matching (contains, equals, starts with, ends with, etc.).
const [columnDefs] = useState([
{ field: 'make', filter: 'agTextColumnFilter' }, // Explicitly define text filter
{ field: 'model' },
{ field: 'price' },
{ field: 'year' },
]);
2. Number Filter (`agNumberColumnFilter`)
Ideal for numeric columns, this filter provides options like equals, not equals, less than, greater than, in range, etc.
const [columnDefs] = useState([
{ field: 'make', filter: 'agTextColumnFilter' },
{ field: 'model' },
{ field: 'price', filter: 'agNumberColumnFilter' }, // Number filter for price
{ field: 'year', filter: 'agNumberColumnFilter' }, // Number filter for year
]);
3. Date Filter (`agDateColumnFilter`)
When dealing with date values, the date filter offers specific comparisons like equals, not equals, before, after, in range.
Note: For agDateColumnFilter to work correctly, your column's data should ideally be JavaScript Date objects or ISO 8601 strings (e.g., "YYYY-MM-DD"). You might need to use a valueFormatter if your date format is different.
const [rowData] = useState([
{ make: "Toyota", model: "Celica", price: 35000, date: '2005-01-01' },
{ make: "Ford", model: "Mondeo", price: 32000, date: '2010-06-15' },
{ make: "Porsche", model: "Boxster", price: 72000, date: '2015-11-30' },
]);
const [columnDefs] = useState([
{ field: 'make', filter: 'agTextColumnFilter' },
{ field: 'model' },
{ field: 'price', filter: 'agNumberColumnFilter' },
{
field: 'date',
filter: 'agDateColumnFilter',
// Optional: Provide a date comparator if your dates aren't standard
filterParams: {
comparator: function(filterLocalDateAtMidnight, cellValue) {
const dateAsString = cellValue;
const dateParts = dateAsString.split('-');
const cellDate = new Date(Number(dateParts[0]), Number(dateParts[1]) - 1, Number(dateParts[2]));
if (cellDate < filterLocalDateAtMidnight) {
return -1;
} else if (cellDate > filterLocalDateAtMidnight) {
return 1;
} else {
return 0;
}
},
}
},
]);
4. Set Filter (`agSetColumnFilter`)
The set filter provides a checkbox list of all unique values in a column, similar to Excel's filter. Users can select one or more values to show only matching rows.
To use agSetColumnFilter, you need to import it from ag-grid-enterprise. If you are using community edition, it's not available by default. For this example, let's assume you have enterprise features available or are using a simplified version.
const [columnDefs] = useState([
{ field: 'make', filter: 'agSetColumnFilter' }, // Set filter for 'make'
{ field: 'model' },
{ field: 'price', filter: 'agNumberColumnFilter' },
]);
The set filter is incredibly intuitive for columns with a limited number of distinct values.
Quick Filter (Global Search)
Beyond column-specific filtering, AG Grid offers a powerful "Quick Filter" feature. This allows users to type into a single input field, and the grid will filter rows across all searchable columns instantly. It's often referred to as a "global search" or "text search".
Implementing the Quick Filter
To implement a quick filter:
- Create an
<input type="text" />element outside your AG Grid component. - Attach an
onChangeevent handler to this input. - In the handler, get the current grid API using
gridRef.current.api. - Call
gridApi.setQuickFilter(value), passing the input's current value.
import React, { useState, useRef, useCallback } from 'react';
import { AgGridReact } from 'ag-grid-react';
import 'ag-grid-community/styles/ag-grid.css';
import 'ag-grid-community/styles/ag-theme-alpine.css';
const MyQuickFilteringGrid = () => {
const gridRef = useRef(null);
const [rowData] = useState([
{ make: "Toyota", model: "Celica", price: 35000, year: 2005 },
{ make: "Ford", model: "Mondeo", price: 32000, year: 2010 },
{ make: "Porsche", model: "Boxster", price: 72000, year: 2015 },
{ make: "BMW", model: "M3", price: 60000, year: 2018 },
{ make: "Audi", model: "A4", price: 45000, year: 2012 },
]);
const [columnDefs] = useState([
{ field: 'make' },
{ field: 'model' },
{ field: 'price' },
{ field: 'year' },
]);
const onFilterTextBoxChanged = useCallback(() => {
gridRef.current.api.setQuickFilter(
document.getElementById('filter-text-box').value
);
}, []);
return (
<div>
<input
type="text"
id="filter-text-box"
placeholder="Quick Filter..."
onInput={onFilterTextBoxChanged} // Use onInput for real-time filtering
style={{ marginBottom: '10px', padding: '8px' }}
/>
<div className="ag-theme-alpine" style={{ height: 400, width: 600 }}>
<AgGridReact
ref={gridRef}
rowData={rowData}
columnDefs={columnDefs}
animateRows={true}
></AgGridReact>
</div>
</div>
);
};
export default MyQuickFilteringGrid;
Now, as you type into the "Quick Filter..." input, the grid will dynamically update, showing only rows that contain the typed text in any of its visible columns.
Managing Filter State (Filter Model)
AG Grid allows you to programmatically get and set the current state of all filters using the "Filter Model". This is incredibly useful for:
- Saving and restoring filter states (e.g., user preferences).
- Applying default filters on grid load.
- Integrating with URL parameters for sharing filtered views.
Getting the Filter Model
To retrieve the current filter state:
// Inside a function or effect where gridApi is available
const currentFilterModel = gridRef.current.api.getFilterModel();
console.log(currentFilterModel);
/* Example Output:
{
make: {
filterType: "text",
type: "contains",
filter: "Toy"
},
price: {
filterType: "number",
type: "greaterThan",
filter: 30000
}
}
*/
Setting the Filter Model
To apply a filter state programmatically:
const applySavedFilter = useCallback(() => {
const savedFilterModel = {
make: {
filterType: 'text',
type: 'contains',
filter: 'Ford',
},
year: {
filterType: 'number',
type: 'greaterThan',
filter: 2010,
},
};
gridRef.current.api.setFilterModel(savedFilterModel);
}, []);
// ... render method
<button onClick={applySavedFilter}>Apply Saved Filter</button>
Calling setFilterModel() will instantly update the grid to reflect the provided filter configuration.
Best Practices for Filtering
- Clear User Feedback: Ensure users know when filters are active (e.g., highlight filtered columns, show a summary of active filters).
- Performance: For extremely large datasets (millions of rows), consider server-side filtering to avoid transferring and processing all data client-side.
- Default Filters: Apply sensible default filters if a specific view is common for users.
- Accessibility: Ensure filter controls are keyboard navigable and screen-reader friendly. AG Grid handles much of this, but be mindful of any custom filter UIs you build.
- Debounce Quick Filter: For very large grids, you might want to debounce the
setQuickFiltercall to avoid excessive re-renders on every keystroke.
Conclusion
Filtering is a cornerstone of effective data grid interaction, and AG Grid React provides a rich and flexible set of tools to implement it. From simple text and number filters to sophisticated set filters and the always-handy quick filter, you have everything you need to empower your users to find exactly what they're looking for.
In our next post in the AG-Grid-React-Series, we'll explore even more advanced features, possibly diving into custom filters or server-side data operations. Stay tuned!