Framework:Javascript Data GridAngular Data GridReact Data GridVue Data Grid

React Data Grid: Filter Component

Filter components allow you to add your own filter types to AG Grid. Use them when the provided filters do not meet your requirements.

Simple Filter

Below is a simple example of filter component as a Hook:

export default forwardRef((props, ref) => {
   const [year, setYear] = useState('All');

   // expose AG Grid Filter Lifecycle callbacks
   useImperativeHandle(ref, () => {
       return {
           doesFilterPass(params) {
               return params.data.year >= 2010;
           },

           isFilterActive() {
               return year === '2010'
           },

           // this example isn't using getModel() and setModel(),
           // so safe to just leave these empty. don't do this in your code!!!
           getModel() {
           },

           setModel() {
           }
       }
   });

   const onYearChange = event => {
       setYear(event.target.value)
   }

   useEffect(() => {
       props.filterChangedCallback()
   }, [year]);

   return (
       <div style={{display: "inline-block", width: "400px"}} onChange={onYearChange}>
           <div style={{padding: "10px", backgroundColor: "#d3d3d3", textAlign: "center"}}>This is a very wide filter</div>
           <label style={{margin: "10px", padding: "50px", display: "inline-block", backgroundColor: "#999999"}}>
               <input type="radio" name="year" value="All" checked={year === 'All'}/> All
           </label>
           <label style={{margin: "10px", padding: "50px", display: "inline-block", backgroundColor: "#999999"}}>
               <input type="radio" name="year" value="2010"/> Since 2010
           </label>
       </div>
   )
});

And here is the same example as a Class-based Component:

export default class YearFilter extends Component {
   constructor(props) {
       super(props);

       this.state = {
           year: "All"
       }
   }

   doesFilterPass(params) {
       return params.data.year >= 2010;
   }

   isFilterActive() {
       return this.state.year === '2010'
   }

   // this example isn't using getModel() and setModel(),
   // so safe to just leave these empty. don't do this in your code!!!
   getModel() {
   }

   setModel() {
   }

   onYearChange(event) {
       this.setState({year: event.target.value},
           () => this.props.filterChangedCallback()
       );
   }

   render() {
       return (
           <div style={{display: "inline-block", width: "400px"}} onChange={this.onYearChange.bind(this)}>
               <div style={{padding: "10px", backgroundColor: "#d3d3d3", textAlign: "center"}}>This is a very wide filter</div>
               <label style={{margin: "10px", padding: "50px", display: "inline-block", backgroundColor: "#999999"}}>
                   <input type="radio" name="year" value="All" checked={this.state.year === 'All'}/> All
               </label>
               <label style={{margin: "10px", padding: "50px", display: "inline-block", backgroundColor: "#999999"}}>
                   <input type="radio" name="year" value="2010" /> Since 2010
               </label>
           </div>
       );
   }
}

Custom Filter Example

The example below shows two custom filters. The first is on the Athlete column and demonstrates a filter with "fuzzy" matching and the second is on the Year column and uses the YearFilter above.

Custom Filter Interface

The interface for a custom filter component is as follows:

interface {
   // Return true if the filter is active. If active then 1) the grid will show the filter icon in the column
   // header and 2) the filter will be included in the filtering of the data.
   isFilterActive(): boolean;

   // The grid will ask each active filter, in turn, whether each row in the grid passes. If any
   // filter fails, then the row will be excluded from the final set. A params object is supplied
   // containing attributes of node (the rowNode the grid creates that wraps the data) and data (the data
   // object that you provided to the grid for that row).
   doesFilterPass(params: IDoesFilterPassParams): boolean;

   // Gets the filter state. If filter is not active, then should return null/undefined.
   // The grid calls getModel() on all active filters when gridApi.getFilterModel() is called.
   getModel(): any;

   // Restores the filter state. Called by the grid after gridApi.setFilterModel(model) is called.
   // The grid will pass undefined/null to clear the filter.
   setModel(model: any): void;

   // Optional methods

   // Gets called when new rows are inserted into the grid. If the filter needs to change its
   // state after rows are loaded, it can do it here. For example the set filters uses this
   // to update the list of available values to select from (e.g. 'Ireland', 'UK' etc for
   // Country filter). To get the list of available values from within this method from the
   // Client Side Row Model, use gridApi.forEachLeafNode(callback)
   onNewRowsLoaded?(): void;

   // Gets called when the column is destroyed. If your custom filter needs to do
   // any resource cleaning up, do it here. A filter is NOT destroyed when it is
   // made 'not visible', as the GUI is kept to be shown again if the user selects
   // that filter again. The filter is destroyed when the column it is associated with is
   // destroyed, either when new columns are set into the grid, or the grid itself is destroyed.
   destroy?(): void;

   // If floating filters are turned on for the grid, but you have no floating filter
   // configured for this column, then the grid will check for this method. If this
   // method exists, then the grid will provide a read-only floating filter for you
   // and display the results of this method. For example, if your filter is a simple
   // filter with one string input value, you could just return the simple string
   // value here.
   getModelAsString?(model: any): string;
}

Note that if you're using Hooks for Grid Components that have lifecycle/callbacks that the grid will call (for example, the doesFilterPass callback from an Editor Component), then you'll need to expose them with forwardRef & useImperativeHandle.

Please refer to the Hook documentation (or the examples on this page) for more information.

Custom Filter Parameters

When a React component is instantiated the grid will make the grid APIs, a number of utility methods as well as the cell & row values available to you via props - the interface for what is provided is documented below.

If the user provides params via the colDef.filterParams attribute, these will be additionally added to the params object, overriding items of the same name if a name clash exists.

Properties available on the IFilterParams interface.

column
The column this filter is for.
colDef
The column definition for the column.
rowModel
IRowModel
The row model, helpful for looking up data values if needed. If the filter needs to know which rows are a) in the table, b) currently visible (i.e. not already filtered), c) which groups, d) what order - all of this can be read from the rowModel.
rowModel: IRowModel;

interface IRowModel {
  // Returns the rowNode at the given index. 
  getRow(index: number): RowNode | undefined;
  // Returns the rowNode for given id. 
  getRowNode(id: string): RowNode | undefined;
  // This is legacy, not used by AG Grid, but keeping for backward compatibility 
  getRowCount(): number;
  getTopLevelRowCount(): number;
  getTopLevelRowDisplayedIndex(topLevelIndex: number): number;
  // Returns the row index at the given pixel 
  getRowIndexAtPixel(pixel: number): number;
  // Returns true if the provided rowNode is in the list of rows to render 
  isRowPresent(rowNode: RowNode): boolean;
  // Returns row top and bottom for a given row 
  getRowBounds(index: number): RowBounds | null;
  // Returns true if this model has no rows, regardless of model filter. EG if rows present, but filtered
  // out, this still returns false. If it returns true, then the grid shows the 'no rows' overlay - but we
  // don't show that overlay if the rows are just filtered out. 
  isEmpty(): boolean;
  // Returns true if no rows (either no rows at all, or the rows are filtered out). This is what the grid
  // uses to know if there are rows to render or not. 
  isRowsToRender(): boolean;
  // Returns all rows in range that should be selected. If there is a gap in range (non ClientSideRowModel) then
  // then no rows should be returned 
  getNodesInRangeForSelection(first: RowNode, last: RowNode | null): RowNode[];
  // Iterate through each node. What this does depends on the model type. For clientSide, goes through
  // all nodes. For serverSide, goes through what's loaded in memory. 
  forEachNode(callback: (rowNode: RowNode, index: number) => void): void;
  // The base class returns the type. We use this instead of 'instanceof' as the client might provide
  // their own implementation of the models in the future. 
  getType(): string;
  // It tells us if this row model knows about the last row that it can produce. This is used by the
  // PaginationPanel, if last row is not found, then the 'last' button is disabled and the last page is
  // not shown. This is always true for ClientSideRowModel. It toggles for InfiniteRowModel. 
  isLastRowIndexKnown(): boolean;
  // Used by CSRM only - is makes sure there are now estimated row heights within the range. 
  ensureRowHeightsValid(startPixel: number, endPixel: number, startLimitIndex: number, endLimitIndex: number): boolean;
  // Gets called after grid is initialised. What happens depends on row model. Client Side will take rowData
  // from gridOptions, the other row models will start calling their datasources. 
  start(): void;
}

interface RowBounds {
  rowTop: number;
  rowHeight: number;
  rowIndex?: number;
}
filterChangedCallback
Function
A function callback to be called when the filter changes. The grid will then respond by filtering the grid data. The callback takes one optional parameter which, if included, will get merged to the FilterChangedEvent object (useful for passing additional information to anyone listening to this event, however such extra attributes are not used by the grid).
filterChangedCallback = (
    additionalEventAttributes?: any
) => void;
filterModifiedCallback
Function
A function callback, to be optionally called, when the filter UI changes. The grid will respond with emitting a FilterModifiedEvent. Apart from emitting the event, the grid takes no further action.
filterModifiedCallback = () => void;
valueGetter
Function
A function callback for the filter to get cell values from the row data. Call with a node to be given the value for that filter's column for that node. The callback takes care of selecting the right column definition and deciding whether to use valueGetter or field etc. This is useful in, for example, creating an Excel style filter, where the filter needs to lookup available values to allow the user to select from.
valueGetter = (rowNode: RowNode) => any;
doesRowPassOtherFilter
Function
A function callback, call with a node to be told whether the node passes all filters except the current filter. This is useful if you want to only present to the user values that this filter can filter given the status of the other filters. The set filter uses this to remove from the list, items that are no longer available due to the state of other filters (like Excel type filtering).
doesRowPassOtherFilter = (rowNode: RowNode) => boolean;
api
GridApi
columnApi
ColumnApi
context
any
The context as provided on gridOptions.context

IDoesFilterPassParams

The method doesFilterPass(params) takes the following as a parameter:

Properties available on the IDoesFilterPassParams interface.

node
The row node in question.
data
any
The data part of the row node in question.

Associating Floating Filter

If you create your own filter you have two options to get floating filters working for that filter:

  1. You can create your own floating filter.
  2. You can implement the getModelAsString() method in your custom filter. If you implement this method and don't provide a custom floating filter, AG Grid will automatically provide a read-only version of a floating filter.

If you don't provide either of these two options for your custom filter, the display area for the floating filter will be empty.

Custom Filters Containing a Popup Element

Sometimes you will need to create custom components for your filters that also contain popup elements. This is the case for Date Filter as it pops up a Date Picker. If the library you use anchors the popup element outside of the parent filter, then when you click on it the grid will think you clicked outside of the filter and hence close the column menu.

There are two ways you can get fix this problem:

  • Add a mouse click listener to your floating element and set it to preventDefault(). This way, the click event will not bubble up to the grid. This is the best solution, but you can only do this if you are writing the component yourself.
  • Add the ag-custom-component-popup CSS class to your floating element. An example of this usage can be found here: Custom Date Component

Accessing the React Component Instance

AG Grid allows you to get a reference to the filter instances via api.getFilterInstance(colKey, callback). React components | are created asynchronously, so it is necessary to use a callback rather than relying on the return value of this method. If your component is a React component, this will give you a reference to AG Grid's component which wraps your React component, | just like Russian Dolls. To get to the wrapped React instance of your component, use the getFrameworkComponentInstance() method as follows:

// let's assume a React component as follows
class NameFilter extends React.Component {
    ... // standard filter methods hidden

    // put a custom method on the filter
    myMethod() {
        // does something
    }
}

// later in your app, if you want to execute myMethod()...
laterOnInYourApplicationSomewhere() {
    // get reference to the AG Grid Filter component on name column
    api.getFilterInstance('name', agGridFilterInstance => {
        // get React instance from the AG Grid instance
        var reactFilterInstance = agGridFilterInstance.getFrameworkComponentInstance();

        // now we're sucking diesel!!!
        reactFilterInstance.myMethod();
    });
}

The example below illustrates how a custom filter component can be accessed and methods on it invoked: