Custom Filter Options defined for a column are also offered in the Advanced Filter, so an expression can use the same options as the column filter.
Configuring Custom Filter Options Copy Link
The Advanced Filter accepts Custom Filter Options the same way as Column Filters. Each Custom Filter Option is an IFilterOptionDef with the following properties.
A unique key that does not clash with the built-in filter keys. |
Display name for the filter. Can be replaced by a locale-specific value using a localeTextFunc. |
Custom filter logic returning a boolean from the filterValues and cellValue; params names the column and the calling filter. |
Number of inputs for this option, and the values an Advanced Filter writes. Defaults to 1, clamped to 0-2. |
Options taking two values are validated like is between: the first value must be less than the second, or equal to it where inRangeInclusive = true.
The predicate only runs with the Client-Side Row Model. With the Server-Side Row Model the option is sent to the server as its displayKey in the filter model, as for the Set Filter options.
The following example demonstrates custom filter options taking different numbers of values:
- The Athlete column has
Starts With A(no values) andDoes Not Start With(one value). - The Age column has
Even Numbers(no values) andBetween (Exclusive)(two values). - The Date column has
Leap Year(no values) andBetween (Exclusive)(two dates).
import {
ClientSideRowModelModule,
DateFilterModule,
GridApi,
GridOptions,
IDateFilterParams,
INumberFilterParams,
ITextFilterParams,
ModuleRegistry,
NumberFilterModule,
TextFilterModule,
createGrid,
enableDevValidations,
} from "ag-grid-community";
import {
AdvancedFilterModule,
ColumnMenuModule,
ContextMenuModule,
} from "ag-grid-enterprise";
import { IOlympicData } from "./interfaces";
if (process.env.NODE_ENV !== "production") {
// Enable extended validations only for development
enableDevValidations();
}
ModuleRegistry.registerModules([
TextFilterModule,
NumberFilterModule,
DateFilterModule,
AdvancedFilterModule,
ClientSideRowModelModule,
ColumnMenuModule,
ContextMenuModule,
]);
let gridApi: GridApi<IOlympicData>;
const athleteFilterParams: ITextFilterParams = {
filterOptions: [
"contains",
{
displayKey: "startsWithA",
displayName: "Starts With A",
numberOfInputs: 0,
predicate: (_, cellValue) =>
cellValue != null && cellValue.startsWith("A"),
},
{
displayKey: "notStartsWith",
displayName: "Does Not Start With",
numberOfInputs: 1,
predicate: ([filterValue], cellValue) =>
cellValue != null &&
!cellValue.toLowerCase().startsWith(String(filterValue).toLowerCase()),
},
],
};
const ageFilterParams: INumberFilterParams = {
filterOptions: [
"equals",
{
displayKey: "evenNumbers",
displayName: "Even Numbers",
numberOfInputs: 0,
predicate: (_, cellValue) => cellValue != null && cellValue % 2 === 0,
},
{
displayKey: "betweenExclusive",
displayName: "Between (Exclusive)",
numberOfInputs: 2,
predicate: ([from, to], cellValue) =>
cellValue != null && cellValue > from && cellValue < to,
},
],
};
const dateFilterParams: IDateFilterParams = {
filterOptions: [
"equals",
{
displayKey: "leapYear",
displayName: "Leap Year",
numberOfInputs: 0,
predicate: (_, cellValue) => {
if (cellValue == null) {
return false;
}
const year = Number(cellValue.split("-")[0]);
return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);
},
},
{
displayKey: "betweenExclusive",
displayName: "Between (Exclusive)",
numberOfInputs: 2,
predicate: ([from, to], cellValue) => {
if (cellValue == null) {
return false;
}
// Built as a local date: the filter's own values are local midnight, and
// `new Date('YYYY-MM-DD')` would be UTC midnight, so the two would not line up.
const [year, month, day] = cellValue.split("-").map(Number);
const cellDate = new Date(year, month - 1, day);
return cellDate > from && cellDate < to;
},
},
],
};
const gridOptions: GridOptions<IOlympicData> = {
columnDefs: [
{ field: "athlete", filterParams: athleteFilterParams },
{ field: "age", minWidth: 120, filterParams: ageFilterParams },
{
field: "date",
filter: "agDateColumnFilter",
filterParams: dateFilterParams,
},
{ field: "sport" },
{ field: "gold" },
],
defaultColDef: {
flex: 1,
minWidth: 180,
filter: true,
},
enableAdvancedFilter: true,
};
const gridDiv = document.querySelector<HTMLElement>("#myGrid")!;
gridApi = createGrid(gridDiv, gridOptions);
fetch("https://www.ag-grid.com/example-assets/olympic-winners.json")
.then((response) => response.json())
.then((data: IOlympicData[]) =>
gridApi!.setGridOption(
"rowData",
// The supplied dates are `dd/mm/yyyy` strings, which is a text column. Convert them to
// `yyyy-mm-dd` so the column is a Date (String) one and its options filter on dates.
data.map((rowData) => {
const [day, month, year] = rowData.date.split("/");
return {
...rowData,
date: `${year}-${month.padStart(2, "0")}-${day.padStart(2, "0")}`,
};
}),
),
);
<div id="myGrid" style="height: 100%"></div>
export interface IOlympicData {
athlete: string,
age: number,
country: string,
year: number,
date: string,
sport: string,
gold: number,
silver: number,
bronze: number,
total: number
} const gridOptions = {
columnDefs: [
{
field: 'age',
filterParams: {
filterOptions: [
'equals',
{
displayKey: 'evenNumbers',
displayName: 'Even Numbers',
numberOfInputs: 0,
predicate: (_values, cellValue) => cellValue != null && cellValue % 2 === 0,
},
{
displayKey: 'betweenExclusive',
displayName: 'Between (Exclusive)',
numberOfInputs: 2,
predicate: ([from, to], cellValue) => cellValue != null && cellValue > from && cellValue < to,
},
],
},
},
],
// other grid options ...
} Using Custom Filter Options in the Advanced Filter Input Copy Link
Custom Filter Options are typed into the Advanced Filter input using their displayName, followed by its values. Using the options from the example above these are some example inputs:
[Athlete] Starts With A
[Athlete] Does Not Start With "Michael"
[Age] Even Numbers
[Age] Between (Exclusive) (30, 40)
[Date] Between (Exclusive) ("2008-08-20", "2008-08-25")Values are quoted according to the column's Cell Data Type, as for the built-in options: numbers are unquoted, everything else is quoted. Two values are separated by a comma; the surrounding brackets are optional. Where the displayKey has a localised entry, that text is used as the option name instead.
A displayKey is resolved against the column being filtered, so different columns can reuse the same key. Reusing an Option Key from the table of standard options, for example contains, replaces that built-in option for the column, the same as it does in the column filter.
Filter Model Copy Link
A condition using a Custom Filter Option stores the displayKey in type, and the values in filter and filterTo. See Filter Model / API for saving and restoring the Advanced Filter state.
const advancedFilterModel = {
filterType: 'number',
colId: 'age',
type: 'betweenExclusive',
filter: 30,
filterTo: 40,
};