Filter Component
Filter components allow you to add your own filter types to ag-Grid. Use this when the provided
filters do not meet your requirements.
Filter Interface
interface IFilterComp {
// mandatory methods
// The init(params) method is called on the filter once. See below for details on the
// parameters.
init(params: IFilterParams): void;
// Returns the GUI for this filter. The GUI can be a) a string of html or b) a DOM element or
// node.
getGui(): any;
// The grid calls this to know if the filter icon in the header should be shown. Return true
// to show.
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
// with attributes 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 for storing
getModel(): any;
// Restores the filter state. Called either as a result of user calling
// OR the floating filter changed (only if using floating filters).
setModel(model: any): void;
// optional methods
// Gets called every time the popup is shown, after the gui returned in
// getGui is attached to the DOM. If the filter popup is closed and reopened, this method is
// called each time the filter is shown. This is useful for any logic that requires attachment
// before executing, such as putting focus on a particular DOM element. The params has one
// callback method 'hidePopup', which you can call at any later point to hide the popup - good
// if you have an 'Apply' button and you want to hide the popup after it is pressed.
afterGuiAttached?(params?: {hidePopup?: Function}): void;
// 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 (eg 'Ireland', 'UK' etc for
// Country filter).
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 new columns are set into the grid, or the grid itself is destroyed.
destroy?(): void;
// Only used in conjunction with floating filters.
//
// 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.
//
// If you are implementing a floating filter for your filter, then leave this method out.
getModelAsString?(model:any): string;
// Only used in conjunction with floating filters.
//
// When a floating filter changes and calls the onFloatingFilterChanged(change) callback then:
// a) filter.onFloatingFilterChanged(change) gets called if it exists.
// ELSE
// b) filter.setModel(model) gets called.
//
// If setModal(modal) is used, then the change object you pass should be the model
// object the filter is expecting. The grid will then continue and update the grids rows
// based on the new filter state.
//
// If onFloatingFilterChanged(change) is used, then the change object you pass
// can be anything you like, as long as it's expected by your filter. The grid will
// update the grid rows for you, you will need to do this yourself by calling filter
// filterChangedCallback() if you need. Use this if your need to do more in your floating
// than setModel() does. For example ag-Grid out of the box filter components use
// this to also consider logic for the Apply button (as if Apply button is active, then
// the filter does not call filterChangedCallback().
onFloatingFilterChanged?(change:any): void;
}
IFilterParams
The method init(params) takes a params object with the items listed 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.
interface IFilterParams {
// The column this filter is for
column: Column;
// The column definition for the column
colDef: ColDef;
// 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 (ie not already filtered), c) what groups d) what order - all of this
// can be read from the rowModel.
rowModel: IRowModel;
// A function callback, to be called, when the filter changes,
// to inform the grid to filter the data. The grid will respond by filtering the data.
filterChangedCallback: ()=> void;
// A function callback, to be optionally called, when the filter changes,
// but before 'Apply' is pressed. The grid does nothing except call
// gridOptions.filterModified(). This is useful if you are making use of
// an 'Apply' button and want to inform the user the filters are not
// longer in sync with the data (until you press 'Apply').
filterModifiedCallback: ()=> void;
// A function callback, call with a node to be given the value for that
// filters column for that node. The callback takes care of selecting the right colDef
// and deciding whether to use valueGetter or field etc. This is useful in, for example,
// creating an Excel style filer, where the filter needs to lookup available values to
// allow the user to select from.
valueGetter: (rowNode: RowNode) => any;
// 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;
// The context for this grid. See section on Context
context: any;
// If the grid options angularCompileFilters is set to true, then a new child
// scope is created for each column filter and provided here. Just ignore this if
// you are not using Angular 1
$scope: any;
// The grid API
api: any;
}
IDoesFilterPassParams
The method doesFilterPass(params) takes the following as a parameter:
interface IDoesFilterPassParams {
// The row node in question
node: RowNode;
// The data part of the row node in question
data: any
}
Associating Floating Filter
If you create your own filter you have two options to get its floating filters working for that filter:
-
You can create your own floating filter.
-
You can implement the method
getModelAsString() in your custom filter. If you implement this method and
you 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 any of these two options for your custom filter, the display area for the floating filter
will be empty.
Custom Filter Example
The example below shows two custom filters. The first is on the Athlete column and the
second is on the Year column.
Angular Filtering
It is possible to provide Angular filters for ag-Grid to use if you are are using the
Angular version of ag-Grid. See
registering framework components for how to register framework components.
Your Angular components need to implement AgFilterComponent. The ag Framework expects to find the
mandatory methods on the interface on the created component (and will call optional methods if they're present).
Angular Params
The ag Framework expects to find the agInit (on the AgFilterComponent interface) method on
the created component, and uses it to supply the 'filter params'.
agInit(params:IFilterParams):void {
this.params = params;
this.valueGetter = params.valueGetter;
}
Angular Methods / Lifecycle
All of the methods in the IFilter interface described above are applicable
to the Angular Component with the following exceptions:
init() is not used. Instead implement the agInit method (on the
AgRendererComponent interface).
destroy() is not used. Instead implement the AngularOnDestroy interface
(ngOnDestroy) for
any cleanup you need to do.
getGui() is not used. Angular will provide the Gui via the supplied template.
After that, all the other methods (onNewRowsLoaded(), getModel(), setModel() etc) behave the
same so put them directly onto your Angular Component.
Accessing the Angular Component Instance
ag-Grid allows you to get a reference to the filter instances via the api.getFilterInstance(colKey)
method. If your component is a Angular component, then this will give you a reference to the ag-Grid's
Component which wraps your Angular Component. Just like Russian Dolls. To get to the wrapped Angular instance
of your component, use the getFrameworkComponentInstance() method as follows:
// lets assume a Angular component as follows
@Component({
selector: 'filter-cell',
template: `
Filter: <input style="height: 10px" #input (ngModelChange)="onChange($event)" [ngModel]="text">
`
})
class PartialMatchFilterComponent implements AgFilterComponent {
... // standard filter methods hidden
// put a custom method on the filter
myMethod() {
// does something
}
}
// then in your app, if you want to execute myMethod()...
laterOnInYourApplicationSomewhere() {
// get reference to the ag-Grid Filter component
let agGridFilter = api.getFilterInstance('name'); // assume filter on name column
// get Angular instance from the ag-Grid instance
let ng2FilterInstance = agGridFilter.getFrameworkComponentInstance();
// now we're sucking diesel!!!
ng2FilterInstance.myMethod();
}
Example: Filtering using Angular Components
Using Angular Components as a partial text Filter in the "Filter Component" column, illustrating filtering and
lifecycle events.
React Filtering
It is possible to provide React filters for ag-Grid to use if you are are using the
React version of ag-Grid. See
registering framework components for how to register framework components.
React Props
The React component will get the 'filter Params' as described above as its React Props.
Therefore you can access all the parameters as React Props.
// React filter Component
class NameFilter extends React.Component {
// did you know that React passes props to your component constructor??
constructor(props) {
super(props);
// from here you can access any of the props!
console.log('The field for this filter is ' + props.colDef.field);
}
// maybe your filter has a button in it, and when it gets clicked...
onButtonWasPressed() {
// all the methods in the props can be called
this.props.filterChangedCallback();
}
}
React Methods / Lifecycle
All of the methods in the IFilter interface described above are applicable
to the React Component with the following exceptions:
init() is not used. Instead use the React props passed to your Component.
destroy() is not used. Instead use the React componentWillUnmount() method for
any cleanup you need to do.
getGui() is not used. Instead do normal React magic in your render() method..
After that, all the other methods (onNewRowsLoaded(), getModel(), setModel() etc) behave the
same so put them directly onto your React Component.
Accessing
the React Component Instance
ag-Grid allows you to get a reference to the filter instances via the api.getFilterInstance(colKey)
method. If your component is a React component, then this will give you a reference to the 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:
// lets 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
}
}
// then in your app, if you want to execute myMethod()...
laterOnInYourApplicationSomewhere() {
// get reference to the ag-Grid Filter component
var agGridFilter = api.getFilterInstance('name'); // assume filter on name column
// get React instance from the ag-Grid instance
var reactFilterInstance = agGridFilter.getFrameworkComponentInstance();
// now we're sucking diesel!!!
reactFilterInstance.myMethod();
}
Example:
Filtering using React Components
Using React Components as a partial text Filter in the "Filter Component" column, illustrating filtering and
lifecycle events.
Polymer Filtering
It is possible to provide Polymer filters for ag-Grid to use if you are are using the
Polymer version of ag-Grid. See
registering framework components for how to register framework components.
Specifying a Polymer Filter
If you are using the ag-grid-polymer component to create the ag-Grid instance,
then you will have the option of additionally specifying the filters
as Polymer components.
// create your filter as a Polymer component
export default class PartialMatchFilter extends PolymerElement {
static get template() {
return html`
Filter: <input style="height: 20px" id="input" on-input="onChange"
value="{{text::input}}">
`;
}
agInit(params) {
this.params = params;
this.valueGetter = params.valueGetter;
}
static get properties() {
return {
text: String
};
}
isFilterActive() {
return this.text !== null && this.text !== undefined && this.text !== '';
}
doesFilterPass(params) {
return this.text.toLowerCase()
.split(" ")
.every((filterWord) => {
return this.valueGetter(params.node).toString().toLowerCase().indexOf(filterWord) >= 0;
});
}
getModel() {
return {value: this.text};
}
setModel(model) {
this.text = model ? model.value : '';
}
afterGuiAttached(params) {
this.$.input.focus();
}
componentMethod(message) {
alert(`Alert from PartialMatchFilterComponent ${message}`);
}
onChange(event) {
let newValue = event.target.value;
if (this.text !== newValue) {
this.text = newValue;
this.params.filterChangedCallback();
}
}
}
customElements.define('partial-match-filter', PartialMatchFilter);
// then reference the Component in your colDef like this
colDef = {
// we use cellRendererFramework instead of cellRenderer
filterFramework: 'partial-match-filter'
// specify all the other fields as normal
headerName: 'Name',
field: 'firstName',
...
}
Your Polymer components need to implement IFilter. The ag Framework expects to find the
mandatory methods on the interface on the created component (and will call optional methods if they're present)
as well as agInit, which the grid uses to provide initial state & parameters.
Polymer Params
The ag Framework expects to find the agInit method on the created component, and uses it to supply the 'filter params'.
agInit(params:IFilterParams):void {
this.params = params;
this.valueGetter = params.valueGetter;
}
Polymer Methods / Lifecycle
All of the methods in the IFilter interface described above are applicable
to the Polymer Component with the following exceptions:
init() is not used. Instead implement the agInit method (on the AgRendererComponent interface).
getGui() is not used. Polymer will provide the Gui via the supplied template.
After that, all the other methods (onNewRowsLoaded(), getModel(), setModel() etc) behave the
same so put them directly onto your Polymer Component.
Accessing the Polymer Component Instance
ag-Grid allows you to get a reference to the filter instances via the api.getFilterInstance(colKey)
method. If your component is a Polymer component, then this will give you a reference to the ag-Grid's
Component which wraps your Polymer Component. Just like Russian Dolls. To get to the wrapped Polymer instance
of your component, use the getFrameworkComponentInstance() method as follows:
// lets assume a Polymer component as follows
export default class PartialMatchFilter extends PolymerElement {
static get template() {
return html`
Filter: <input style="height: 20px" id="input" on-input="onChange"
value="{{text::input}}">
`;
}
... // standard filter methods hidden
// put a custom method on the filter
componentMethod() {
// does something
}
}
// then in your app, if you want to execute myMethod()...
laterOnInYourApplicationSomewhere() {
// get reference to the ag-Grid Filter component
let agGridFilter = this.gridOptions.api.getFilterInstance("name");
// assume filter on name column
let agGridFilter = api.getFilterInstance('name');
// get Polymer instance from the ag-Grid instance
let polymerFilterInstance = getFrameworkComponentInstance();
// now we're sucking diesel!!!
polymerFilterInstance.componentMethod("Hello World!");
}
Example: Filtering using Polymer Components
Using Polymer Components as a partial text Filter in the "Filter Component" column, illustrating filtering and lifecycle events.
VueJS Filtering
It is possible to provide VueJS filters for ag-Grid to use if you are are using the
VueJS version of ag-Grid. See
registering framework components for how to register framework components.
VueJS Params
The 'filter params' will be made available implicitly in a data value names params. This value will be
available to
you from the created VueJS lifecycle hook.
You can think of this as you having defined the following:
export default {
data () {
return {
params: null
}
},
...
but you do not need to do this - this is made available to you behind the scenes, and contains the cells value.
VueJS Methods / Lifecycle
All of the methods in the IFilter interface described above are applicable
to the VueJS Component with the following exceptions:
init() is not used. The cells value is made available implicitly via a data field called params.
getGui() is not used. VueJS will provide the Gui via the supplied template.
After that, all the other methods (onNewRowsLoaded(), getModel(), setModel() etc) behave the
same so put them directly onto your VueJS Component.
Accessing the VueJS Component Instance
ag-Grid allows you to get a reference to the filter instances via the api.getFilterInstance(colKey)
method. If your component is a VueJS component, then this will give you a reference to the ag-Grid's
Component which wraps your VueJS Component. Just like Russian Dolls. To get to the wrapped VueJS instance
of your component, use the getFrameworkComponentInstance() method as follows:
// lets assume a VueJS component as follows
export default Vue.extend({
template: `<input style="height: 20px" :ref="'input'" v-model="text">`,
data() {
...data
},
methods: {
componentMethod(message) {
alert(`Alert from PartialMatchFilterComponent ${message}`);
},
...other methods
// then in your app, if you want to execute myMethod()...
laterOnInYourApplicationSomewhere() {
// get reference to the ag-Grid Filter component
let agGridFilter = api.getFilterInstance('name'); // assume filter on name column
// get VueJS instance from the ag-Grid instance
let vueFilterInstance = agGridFilter.getFrameworkComponentInstance();
// now we're sucking diesel!!!
vueFilterInstance.componentMethod();
}
Aurelia Filtering
For an example on Aurelia filtering, see the
ag-grid-aurelia-example on Github.
Specifying a Filter in an Aurelia project
If you are using the ag-grid-aurelia component to create the ag-Grid instance,
then you will have the option of additionally specifying the filters
as Aurelia components.
// create your filter as Filter Component
export default class PartialMatchFilter implements IFilter {
private params: IFilterParams;
private valueGetter: (rowNode: RowNode) => any;
private filterText: any;
private eGui: HTMLElement;
private eFilterText: any;
public init(params: IFilterParams): void {
this.params = params;
this.filterText = null;
this.valueGetter = params.valueGetter;
};
public getGui() {
this.eGui = document.createElement('div');
this.eGui.innerHTML =
'<input style="margin: 4px 0px 4px 0px;" type="text" id="filterText" placeholder="Full name search..."/>';
this.eFilterText = this.eGui.querySelector('#filterText');
this.eFilterText.addEventListener("changed", listener);
this.eFilterText.addEventListener("paste", listener);
this.eFilterText.addEventListener("input", listener);
// IE doesn't fire changed for special keys (eg delete, backspace), so need to
// listen for this further ones
this.eFilterText.addEventListener("keydown", listener);
this.eFilterText.addEventListener("keyup", listener);
var that = this;
function listener(event) {
that.filterText = event.target.value;
that.params.filterChangedCallback();
}
return this.eGui;
};
isFilterActive(): boolean {
return this.filterText !== null && this.filterText !== undefined && this.filterText !== '';
}
doesFilterPass(params: IDoesFilterPassParams): boolean {
// make sure each word passes separately, ie search for firstname, lastname
let passed = true;
this.filterText.toLowerCase().split(" ").forEach((filterWord) => {
let value = this.valueGetter(<any>params);
if (value.toString().toLowerCase().indexOf(filterWord) < 0) {
passed = false;
}
});
return passed;
}
getModel(): any {
var model = {value: this.filterText.value};
return model;
}
setModel(model: any): void {
this.eFilterText.value = model.value;
}
afterGuiAttached(params: IAfterFilterGuiAttachedParams): void {
this.eGui.focus();
}
}
// provide a method that returns the name of the class to use as a filter (in the parent component)
getPartialMatchFilter() {
return PartialMatchFilter;
}
// then reference the Component in your column definitions like this
<ag-grid-column header-name="Filter Component" field="name" width.bind="198" filter.bind="getPartialMatchFilter()"></ag-grid-column>