# Ag-Grid Custom Filtering

**URL:** <https://community.plotly.com/t/ag-grid-custom-filtering/79061>\
**Category:** Dash Python\
**Created:** [October 5, 2023, 10:11pm UTC](https://community.plotly.com/t/ag-grid-custom-filtering/79061 "2023-10-05T22:11:55Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![robertf](https://avatars.discourse-cdn.com/v4/letter/r/a4c791/32.png) [@robertf](https://community.plotly.com/u/robertf)\
**Post date:** [October 5, 2023, 10:11pm UTC](https://community.plotly.com/t/ag-grid-custom-filtering/79061/1 "2023-10-05T22:11:55Z")

</div>

Hello All,

I’ve been trying to understand this for a while, and before I continue I’d like to know if dash ag-grid supports what I’m looking for.

- Does it currently support creating/using custom filter components? [React Data Grid: Filter Component](https://www.ag-grid.com/react-data-grid/component-filter/)
- Does it currently support textMatcher? [React Data Grid: Text Filter](https://www.ag-grid.com/react-data-grid/filter-text/#text-custom-matcher)

If these can be done in the current version of dash ag-grid, could someone provide a small example of each? I am not a React developer so I’m having a hard time translating the official Ag-Grid docs.

Thanks!

---

<div class="post-metadata">

**Author:** ![AnnMarieW](https://avatars.discourse-cdn.com/v4/letter/a/ec9cab/32.png) [@AnnMarieW](https://community.plotly.com/u/AnnMarieW)\
**Post date:** [October 6, 2023, 2:49pm UTC](https://community.plotly.com/t/ag-grid-custom-filtering/79061/2 "2023-10-06T14:49:19Z")

</div>

Hi @robertf

Yes Dash AG Grid supports both – but it does require a little React of JavaScript to customize. If you give more details about what you are trying to do, it will be easier to help.

---

<div class="post-metadata">

**Author:** ![robertf](https://avatars.discourse-cdn.com/v4/letter/r/a4c791/32.png) [@robertf](https://community.plotly.com/u/robertf)\
**Post date:** [October 6, 2023, 3:22pm UTC](https://community.plotly.com/t/ag-grid-custom-filtering/79061/3 "2023-10-06T15:22:43Z")

</div>

Hello @AnnMarieW

I have an example app below that I believe can use a custom filter component if possible (using textMatcher was just an idea in case it can also work somehow). What I’m wanting to do is very niche so I understand if the reasoning doesn’t make sense. For this example, I’m wanting to show a parent row with all of its children if a filter for a column passes. So if I filter the “Employment Type” column for “contains Contract” I want to see everyone under Brittany Hanson and Francis Strickland. (I know it seems weird, but I do want to see everyone under the parent.)

```auto
import dash_ag_grid as dag
from dash import Dash, Input, Output, html, dcc
import dash_bootstrap_components as dbc
import os

app = Dash( __name__ )

rowData = [
    {
        "orgHierarchy": ["Erica Rogers"],
        "jobTitle": "CEO",
        "employmentType": "Permanent",
    },
    {
        "orgHierarchy": ["Erica Rogers", "Malcolm Barrett"],
        "jobTitle": "Exec. Vice President",
        "employmentType": "Permanent",
    },
    {
        "orgHierarchy": ["Erica Rogers", "Esther Baker"],
        "jobTitle": "Director of Operations",
        "employmentType": "Permanent",
    },
    {
        "orgHierarchy": [
            "Brittany Hanson",
        ],
        "jobTitle": "Fleet Coordinator",
        "employmentType": "Permanent",
    },
    {
        "orgHierarchy": [
            "Brittany Hanson",
            "Leah Flowers",
        ],
        "jobTitle": "Parts Technician",
        "employmentType": "Contract",
    },
    {
        "orgHierarchy": [
            "Brittany Hanson",
            "Tammy Sutton",
        ],
        "jobTitle": "Service Technician",
        "employmentType": "Contract",
    },
    {
        "orgHierarchy": [
            "Brittany Hanson",
            "Derek Paul",
        ],
        "jobTitle": "Inventory Control",
        "employmentType": "Permanent",
    },
    {
        "orgHierarchy": ["Francis Strickland"],
        "jobTitle": "VP Sales",
        "employmentType": "Permanent",
    },
    {
        "orgHierarchy": [
            "Francis Strickland",
            "Morris Hanson",
        ],
        "jobTitle": "Sales Manager",
        "employmentType": "Permanent",
    },
    {
        "orgHierarchy": [
            "Francis Strickland",
            "Todd Tyler",
        ],
        "jobTitle": "Sales Executive",
        "employmentType": "Contract",
    },
    {
        "orgHierarchy": [
            "Francis Strickland",
            "Bennie Wise",
        ],
        "jobTitle": "Sales Executive",
        "employmentType": "Contract",
    },
    {
        "orgHierarchy": [
            "Francis Strickland",
            "Joel Cooper",
        ],
        "jobTitle": "Sales Executive",
        "employmentType": "Permanent",
    },
]

grid = html.Div(
    [
        dag.AgGrid(
            id="tree-data-example",
            columnDefs=[
                # we're using the auto group column by default!
                {"field": "jobTitle"},
                {"field": "employmentType"},
            ],
            defaultColDef={
                "flex": 1,
                "filter": 'agTextColumnFilter'
            },
            dashGridOptions={
                "autoGroupColumnDef": {
                    "headerName": "Organisation Hierarchy",
                    "minWidth": 300,
                    "cellRendererParams": {
                        "suppressCount": True,
                    },
                },
                "groupDefaultExpanded": -1,
                "getDataPath": {"function": "getDataPath(params)"},
                "treeData": True,
            },
            rowData=rowData,
            enableEnterpriseModules=True,
            licenseKey = os.environ['AGGRID_ENTERPRISE'],
            style={'height': 600}
        ),
    ]
)

app.layout = html.Div(
    [
        dcc.Markdown("Example: Organisational Hierarchy using Tree Data "),
        grid,
    ]
)

if __name__ == " __main__":
    app.run(debug=True)

```

To run this example, include the following in the dashAgGridFunctions.js file in your app’s assets folder

```auto
var dagfuncs = window.dashAgGridFunctions = window.dashAgGridFunctions || {};

dagfuncs.getDataPath = function (data) {
    return data.orgHierarchy;
}

```

Thanks for any direction you can provide!

---

<div class="post-metadata">

**Author:** ![AnnMarieW](https://avatars.discourse-cdn.com/v4/letter/a/ec9cab/32.png) [@AnnMarieW](https://community.plotly.com/u/AnnMarieW)\
**Post date:** [October 6, 2023, 4:18pm UTC](https://community.plotly.com/t/ag-grid-custom-filtering/79061/4 "2023-10-06T16:18:31Z")

</div>

Ah yes - the Tree data is an AG Grid Enterprise feature. I’m not sure if there is an easy workaround to do this in the community version.

> **[React Data Grid: Tree Data](https://www.ag-grid.com/react-data-grid/tree-data/)**
>
> Use Tree Data to display data that has parent / child relationships where the parent / child relationships are provided
> as part of the data. Download v30 of the best React Data Grid in the world now.

---

<div class="post-metadata">

**Author:** ![robertf](https://avatars.discourse-cdn.com/v4/letter/r/a4c791/32.png) [@robertf](https://community.plotly.com/u/robertf)\
**Post date:** [October 6, 2023, 4:40pm UTC](https://community.plotly.com/t/ag-grid-custom-filtering/79061/5 "2023-10-06T16:40:39Z")

</div>

So for this I have been using the enterprise version of Ag Grid (so this is ok for the example I provided). I can’t think of a good example to provide that doesn’t use tree data.  
Maybe something silly like, if someone filters the “Employment Type” column, the custom filter component will instead filter the “Job Title” column. The example code above can be used except delete references to using the enterprise version of ag-grid.

I’m mostly looking for a skeleton on how to implement what I’m looking for with tree data. The attempts I’ve made so far haven’t worked out since I don’t understand the Ag-Grid to Dash Ag-Grid conversion.

---

<div class="post-metadata">

**Author:** ![AnnMarieW](https://avatars.discourse-cdn.com/v4/letter/a/ec9cab/32.png) [@AnnMarieW](https://community.plotly.com/u/AnnMarieW)\
**Post date:** [October 6, 2023, 5:38pm UTC](https://community.plotly.com/t/ag-grid-custom-filtering/79061/6 "2023-10-06T17:38:56Z")

</div>

Oh, sorry - I didn’t look closely at your example. I saw the tree data and thought the issue was that you were trying to use an Enterprise feature with Community.

Since you have Enterprise, I think there are easier ways to accomplish this rather than using custom filters (although that might work too). I have some ideas but I’d like to try them first. I’m out of the office today - I’ll post what I find in a bit.

---

<div class="post-metadata">

**Author:** ![robertf](https://avatars.discourse-cdn.com/v4/letter/r/a4c791/32.png) [@robertf](https://community.plotly.com/u/robertf)\
**Post date:** [October 6, 2023, 6:01pm UTC](https://community.plotly.com/t/ag-grid-custom-filtering/79061/7 "2023-10-06T18:01:34Z")

</div>

Oh no worries! I appreciate any help or leads with this. I’ll continue to look into a solution as well and will post something if I am able to figure something out.

---

<div class="post-metadata">

**Author:** ![AnnMarieW](https://avatars.discourse-cdn.com/v4/letter/a/ec9cab/32.png) [@AnnMarieW](https://community.plotly.com/u/AnnMarieW)\
**Post date:** [October 6, 2023, 6:03pm UTC](https://community.plotly.com/t/ag-grid-custom-filtering/79061/8 "2023-10-06T18:03:40Z")

</div>

Tree list filters is one of the things that might work: [React Data Grid: Set Filter - Tree List](https://www.ag-grid.com/react-data-grid/filter-set-tree-list/)

---

<div class="post-metadata">

**Author:** ![robertf](https://avatars.discourse-cdn.com/v4/letter/r/a4c791/32.png) [@robertf](https://community.plotly.com/u/robertf)\
**Post date:** [October 7, 2023, 6:13pm UTC](https://community.plotly.com/t/ag-grid-custom-filtering/79061/9 "2023-10-07T18:13:46Z")

</div>

Thanks Ann. I tested out the suggestion but wasn’t able to get anywhere. I am going to try and recreate the example they used here for Filter Components: [React Data Grid: Filter Component](https://www.ag-grid.com/react-data-grid/component-filter/) so that I directly compare to a working example.

---

<div class="post-metadata">

**Author:** ![AnnMarieW](https://avatars.discourse-cdn.com/v4/letter/a/ec9cab/32.png) [@AnnMarieW](https://community.plotly.com/u/AnnMarieW)\
**Post date:** [October 7, 2023, 6:18pm UTC](https://community.plotly.com/t/ag-grid-custom-filtering/79061/10 "2023-10-07T18:18:21Z")

</div>

Hi @robertf

I’m not sure I understand your use-case exactly. It would be helpful if you could create an example, even if it was in excel. I’m concerned that users might find it confusing if the grid sorted on a different column than where the filter was entered.

---

<div class="post-metadata">

**Author:** ![robertf](https://avatars.discourse-cdn.com/v4/letter/r/a4c791/32.png) [@robertf](https://community.plotly.com/u/robertf)\
**Post date:** [October 7, 2023, 9:01pm UTC](https://community.plotly.com/t/ag-grid-custom-filtering/79061/11 "2023-10-07T21:01:39Z")

</div>

Hello Ann. So I went ahead and made a new example with a simpler use case. I am copying the first example from the Ag-Grid Docs page: [JavaScript Data Grid: Filter Component](https://www.ag-grid.com/javascript-data-grid/component-filter/)  
I am stuck on getting the YearFilter to work exactly as they did. I believe I need to convert their raw html code into something more compatible with Dash, so I am using dash\_core\_components for the radio-items. After I learn more about the method to get this to work, I can then tackle the PersonFilter.

```auto
from dash import Dash, html
import dash_ag_grid as dag
import pandas as pd

app = Dash( __name__ )

df = pd.read_json('https://www.ag-grid.com/example-assets/olympic-winners.json', convert_dates=False)

rowData = df.to_dict('records')

columnDefs = [
    # { 'field': 'athlete', 'minWidth': 150, 'filter': 'PersonFilter' },
    { 'field': 'age', 'filter': 'agNumberColumnFilter' },
    { 'field': 'country', 'minWidth': 150 },
    { 'field': 'year', 'filter': 'YearFilter' },
    {
      'field': 'date',
      'minWidth': 130,
      'filter': 'agDateColumnFilter',
      'filterParams': {
        'comparator': {'function':'dateComparator'},
      },
    },
    { 'field': 'sport' },
    { 'field': 'gold', 'filter': 'agNumberColumnFilter' },
    { 'field': 'silver', 'filter': 'agNumberColumnFilter' },
    { 'field': 'bronze', 'filter': 'agNumberColumnFilter' },
    { 'field': 'total', 'filter': 'agNumberColumnFilter' },
]

defaultColDef = {
    'editable': True,
    'sortable': True,
    'flex': 1,
    'minWidth': 100,
    'filter': True,
    'resizable': True,
}

app.layout = html.Div(
    [
        dag.AgGrid(
            id="filter-component-example",
            columnDefs=columnDefs,
            rowData=rowData,
            defaultColDef=defaultColDef
        ),
    ]
)

if __name__ == " __main__":
    app.run(host="127.0.0.1", debug=True)

```

dashAgGridFunctions.js

```auto
var dagfuncs = window.dashAgGridFunctions = window.dashAgGridFunctions || {};

dagfuncs.dateComparator = function (filterLocalDateAtMidnight, cellValue) {

    const dateAsString = cellValue;
    const dateParts = dateAsString.split('/');
    const cellDate = new Date(
        Number(dateParts[2]),
        Number(dateParts[1]) - 1,
        Number(dateParts[0])
    );
    if (filterLocalDateAtMidnight.getTime() === cellDate.getTime()) {
        return 0;
    }
    if (cellDate < filterLocalDateAtMidnight) {
        return -1;
    }
    if (cellDate > filterLocalDateAtMidnight) {
        return 1;
    }

}

```

dashAgGridComponentFunctions.js

```auto
var dagcomponentfuncs = (window.dashAgGridComponentFunctions = window.dashAgGridComponentFunctions || {});

dagcomponentfuncs.YearFilter = function (params) {

    const filterActive = false;

    function onChanged() {
        filterActive = this.checked;
        params.filterChangedCallback();
      }
    
    function doesFilterPass(params) {
        return params.data.year >= 2010;
      }
    
    function isFilterActive() {
        return filterActive;
      }

    return React.createElement(
        window.dash_core_components.RadioItems,
        {
            options:[
                {'label': 'All', 'value': 'all'},
                {'label': 'Since 2010', 'value': '2010'},
            ],
            value:'all',
            onChange:onChanged
        },
        null
        )
};

```

---

<div class="post-metadata">

**Author:** ![robertf](https://avatars.discourse-cdn.com/v4/letter/r/a4c791/32.png) [@robertf](https://community.plotly.com/u/robertf)\
**Post date:** [October 12, 2023, 1:34pm UTC](https://community.plotly.com/t/ag-grid-custom-filtering/79061/12 "2023-10-12T13:34:43Z")

</div>

Hello @AnnMarieW

With the latest example I provided, does it look like I’m on the right track to get the YearFilter to work? I’m having trouble understanding how to make the RadioItems function as the example docs did.

---

<div class="post-metadata">

**Author:** ![AnnMarieW](https://avatars.discourse-cdn.com/v4/letter/a/ec9cab/32.png) [@AnnMarieW](https://community.plotly.com/u/AnnMarieW)\
**Post date:** [October 12, 2023, 2:03pm UTC](https://community.plotly.com/t/ag-grid-custom-filtering/79061/13 "2023-10-12T14:03:24Z")

</div>

Hi @robertf

Yes, you made a good start. I also got stuck on making the RadioItems function. This works slightly different from components in cell.

I think we need some guidance from the Dash AG Grid guru @jinnyzor

---

<div class="post-metadata">

**Author:** ![jinnyzor](https://sea2.discourse-cdn.com/flex024/user_avatar/community.plotly.com/jinnyzor/32/21194_2.png) [@jinnyzor](https://community.plotly.com/u/jinnyzor)\
**Post date:** [October 12, 2023, 5:51pm UTC](https://community.plotly.com/t/ag-grid-custom-filtering/79061/14 "2023-10-12T17:51:16Z")

</div>

Hello @robertf,

There isnt currently a way to do this, but I have a [PR](https://github.com/plotly/dash-ag-grid/pull/243) pending that will fix it so that you can do something like this:

app.py

```auto
from dash import Dash, html
import dash_ag_grid as dag
import pandas as pd

app = Dash( __name__ )

df = pd.read_csv(
    "https://raw.githubusercontent.com/plotly/datasets/master/ag-grid/olympic-winners.csv"
)

rowData = df.to_dict('records')

columnDefs = [
    { 'field': 'age', 'filter': 'agNumberColumnFilter' },
    { 'field': 'country', 'minWidth': 150 },
    { 'field': 'year', 'filter': {'function': 'YearFilter'}},
    {
      'field': 'date',
      'minWidth': 130,
      'filter': 'agDateColumnFilter',
      'filterParams': {
        'comparator': {'function':'dateComparator'},
      },
    },
    { 'field': 'sport' },
    { 'field': 'gold', 'filter': 'agNumberColumnFilter' },
    { 'field': 'silver', 'filter': 'agNumberColumnFilter' },
    { 'field': 'bronze', 'filter': 'agNumberColumnFilter' },
    { 'field': 'total', 'filter': 'agNumberColumnFilter' },
]

defaultColDef = {
    'editable': True,
    'sortable': True,
    'flex': 1,
    'minWidth': 100,
    'filter': True,
    'resizable': True,
}

app.layout = html.Div(
    [
        html.H3("See the custom filter component in the Year column"),
        dag.AgGrid(
            id="grid",
            columnDefs=columnDefs,
            rowData=rowData,
            defaultColDef=defaultColDef
        ),
    ]
)

if __name__ == " __main__":
    app.run(debug=True)

```

dashAgGridFunctions.js

This example was adapted from [React Data Grid: Filter Component](https://www.ag-grid.com/react-data-grid/component-filter/)  
The only differences are:

- React.createElement instead of JSX
- setProps, which all Dash components use to report user interactions, nstead of a plain js event handler

```auto
var dagfuncs = window.dashAgGridFunctions = window.dashAgGridFunctions || {};

const [useImperativeHandle, useState, useEffect, forwardRef, Component] = [React.useImperativeHandle, React.useState, React.useEffect, React.forwardRef, React.component]

dagfuncs.YearFilter = forwardRef((props, ref) => {
   const [year, setYear] = useState('All');

   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() {
           }
       }
   });

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

    setProps = (props) => {
        if (props.value) {
            setYear(props.value)
        }
    }

    return React.createElement(
        window.dash_core_components.RadioItems,
        {
            options:[
                {'label': 'All', 'value': 'All'},
                {'label': 'Since 2010', 'value': '2010'},
            ],
            value: year,
            setProps
        }
        )
});

dagfuncs.dateComparator = function (filterLocalDateAtMidnight, cellValue) {

    const dateAsString = cellValue;
    const dateParts = dateAsString.split('/');
    const cellDate = new Date(
        Number(dateParts[2]),
        Number(dateParts[1]) - 1,
        Number(dateParts[0])
    );
    if (filterLocalDateAtMidnight.getTime() === cellDate.getTime()) {
        return 0;
    }
    if (cellDate < filterLocalDateAtMidnight) {
        return -1;
    }
    if (cellDate > filterLocalDateAtMidnight) {
        return 1;
    }

}

```

---

<div class="post-metadata">

**Author:** ![robertf](https://avatars.discourse-cdn.com/v4/letter/r/a4c791/32.png) [@robertf](https://community.plotly.com/u/robertf)\
**Post date:** [October 14, 2023, 6:21pm UTC](https://community.plotly.com/t/ag-grid-custom-filtering/79061/15 "2023-10-14T18:21:41Z")

</div>

Thanks @jinnyzor! I’ll test this out as soon as I can. Then I’ll attempt to expand upon it and get the PersonFilter to work.

---

<div class="post-metadata">

**Author:** ![AnnMarieW](https://avatars.discourse-cdn.com/v4/letter/a/ec9cab/32.png) [@AnnMarieW](https://community.plotly.com/u/AnnMarieW)\
**Post date:** [October 14, 2023, 6:30pm UTC](https://community.plotly.com/t/ag-grid-custom-filtering/79061/16 "2023-10-14T18:30:08Z")

</div>

Hi @robertf

Please note that the PR has not been merged or released yet. This will likely happen sometime next week. 🤞

This will be available on **dash-ag-grid\>=2.4.0**

---

<div class="post-metadata">

**Author:** ![AnnMarieW](https://avatars.discourse-cdn.com/v4/letter/a/ec9cab/32.png) [@AnnMarieW](https://community.plotly.com/u/AnnMarieW)\
**Post date:** [October 21, 2023, 4:36pm UTC](https://community.plotly.com/t/ag-grid-custom-filtering/79061/17 "2023-10-21T16:36:21Z")

</div>

Hi @robertf

🎉 dash-ag-grid-2.4.0 is now available!

The example that @jinnyzor [posted above now works](https://community.plotly.com/t/ag-grid-custom-filtering/79061/14). It shows how to use a custom component in the header to filter the grid. This example uses `dcc.RadioItems`

As a bonus, it also demonstrates how to filter the Date column using a date filter comparator function in JavaScript. You can use this instead of the `d3.timeParse`. More info in the dash docs [date filters](https://dash.plotly.com/dash-ag-grid/date-filters#date-filter-comparator) section.

![ag-grid-custom-function](https://us1.discourse-cdn.com/flex024/uploads/plot/original/3X/4/6/464744825de3bc12ff1492af04654b0c05d8ef2b.gif)

dag-docs

---

<div class="post-metadata">

**Author:** ![robertf](https://avatars.discourse-cdn.com/v4/letter/r/a4c791/32.png) [@robertf](https://community.plotly.com/u/robertf)\
**Post date:** [October 23, 2023, 12:46pm UTC](https://community.plotly.com/t/ag-grid-custom-filtering/79061/18 "2023-10-23T12:46:30Z")

</div>

Thanks @jinnyzor and @AnnMarieW ! I’ll be working with this again soon and will report back if I am having issues adapting this to my use case.

---

<div class="post-metadata">

**Author:** ![robertf](https://avatars.discourse-cdn.com/v4/letter/r/a4c791/32.png) [@robertf](https://community.plotly.com/u/robertf)\
**Post date:** [October 31, 2023, 7:49pm UTC](https://community.plotly.com/t/ag-grid-custom-filtering/79061/19 "2023-10-31T19:49:20Z")

</div>

Hello @jinnyzor

I took some time to apply what you showed towards creating the PersonFilter from the docs. I am also wanting to add an Apply and Remove/Clear button, since it currently is actively filtering as the person types. I have things mostly working, except I am not able to figure out how to delay applying the filter or how to clear it. I tried a few things (like trying to save as a global variable) but nothing works. Also, I am not able to clear the textbox after typing in it (the 1st character always stays.)

Below is what I have so far.

app.py

```auto
from dash import Dash, html
import dash_ag_grid as dag
import pandas as pd

app = Dash( __name__ )

df = pd.read_json('https://www.ag-grid.com/example-assets/olympic-winners.json', convert_dates=False)

rowData = df.to_dict('records')

columnDefs = [
    { 'field': 'athlete', 'minWidth': 150, 'filter': {'function': 'PersonFilter' } },
    { 'field': 'age', 'filter': 'agNumberColumnFilter' },
    { 'field': 'country', 'minWidth': 150 },
    # { 'field': 'year', 'filter': {'function': 'YearFilter' }},
    {
      'field': 'date',
      'minWidth': 130,
      'filter': 'agDateColumnFilter',
      'filterParams': {
        'comparator': {'function':'dateComparator'},
      },
    },
    { 'field': 'sport' },
    { 'field': 'gold', 'filter': 'agNumberColumnFilter' },
    { 'field': 'silver', 'filter': 'agNumberColumnFilter' },
    { 'field': 'bronze', 'filter': 'agNumberColumnFilter' },
    { 'field': 'total', 'filter': 'agNumberColumnFilter' },
]

defaultColDef = {
    'editable': True,
    'sortable': True,
    'flex': 1,
    'minWidth': 100,
    'filter': True,
    'resizable': True,
}

app.layout = html.Div(
    [
        dag.AgGrid(
            id="filter-component-example",
            columnDefs=columnDefs,
            rowData=rowData,
            defaultColDef=defaultColDef
        ),
    ]
)

if __name__ == " __main__":
    app.run(host="127.0.0.1", debug=True)

```

dashAgGridFunctions.js

```auto
var dagfuncs = window.dashAgGridFunctions = window.dashAgGridFunctions || {};

const [useImperativeHandle, useRef, useState, useEffect, forwardRef, Component] = [React.useImperativeHandle, React.useRef, React.useState, React.useEffect, React.forwardRef, React.component]

dagfuncs.PersonFilter = forwardRef((props, ref) => {
    const [filterText, setFilterText] = useState(null);

  // expose AG Grid Filter Lifecycle callbacks
  useImperativeHandle(ref, () => {
    return {
      doesFilterPass(params) {
        const { api, colDef, column, columnApi, context } = props;
        const { node } = params;

        // make sure each word passes separately, ie search for firstname, lastname
        let passed = true;
        filterText
          .toLowerCase()
          .split(' ')
          .forEach((filterWord) => {
            const value = props.valueGetter({
              api,
              colDef,
              column,
              columnApi,
              context,
              data: node.data,
              getValue: (field) => node.data[field],
              node,
            });

            if (value.toString().toLowerCase().indexOf(filterWord) < 0) {
              passed = false;
            }
          });

        return passed;
      },

      isFilterActive() {
        return filterText != null && filterText !== '';
      },

      getModel() {
        if (!this.isFilterActive()) {
          return null;
        }

        return { value: filterText };
      },

      setModel(model) {
        setFilterText(model == null ? null : model.value);
      },
    };
  });

  setProps = (props) => {
    if (props.value) {
        setFilterText(props.value)
    }
    };

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

  function buttonOnApply(){
    console.log('applied');
  };

  function buttonOnRemove(){
    console.log('filter removed');
  };

  return React.createElement(
    'div',
    {},
    [
        React.createElement(window.dash_core_components.Input, {type:'text', placeholder:'enter text', value:filterText, setProps}),
        React.createElement('button', {onClick:buttonOnApply}, 'Apply'),
        React.createElement('button', {onClick:buttonOnRemove}, 'Remove Filter'),
    ]
  )

});

```

---

<div class="post-metadata">

**Author:** ![jinnyzor](https://sea2.discourse-cdn.com/flex024/user_avatar/community.plotly.com/jinnyzor/32/21194_2.png) [@jinnyzor](https://community.plotly.com/u/jinnyzor)\
**Post date:** [October 31, 2023, 8:00pm UTC](https://community.plotly.com/t/ag-grid-custom-filtering/79061/20 "2023-10-31T20:00:49Z")

</div>

Hello @robertf,

You were close, try this:

```auto
dagfuncs.PersonFilter = forwardRef((props, ref) => {
    const [filterText, setFilterText] = useState(null);

  // expose AG Grid Filter Lifecycle callbacks
  useImperativeHandle(ref, () => {
    return {
      doesFilterPass(params) {
        const { api, colDef, column, columnApi, context } = props;
        const { node } = params;

        // make sure each word passes separately, ie search for firstname, lastname
        let passed = true;
        filterText
          .toLowerCase()
          .split(' ')
          .forEach((filterWord) => {
            const value = props.valueGetter({
              api,
              colDef,
              column,
              columnApi,
              context,
              data: node.data,
              getValue: (field) => node.data[field],
              node,
            });

            if (value.toString().toLowerCase().indexOf(filterWord) < 0) {
              passed = false;
            }
          });

        return passed;
      },

      isFilterActive() {
        return filterText != null && filterText !== '';
      },

      getModel() {
        if (!this.isFilterActive()) {
          return null;
        }

        return { value: filterText };
      },

      setModel(model) {
        setFilterText(model == null ? null : model.value);
      },
    };
  });

  setProps = ({value}) => {
        setFilterText(value)
    };

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

  function buttonOnApply(){
    console.log('applied');
  };

  function buttonOnRemove(){
    console.log('filter removed');
    setFilterText('')
  };

  return React.createElement(
    'div',
    {},
    [
        React.createElement(window.dash_core_components.Input, {type:'text', placeholder:'enter text', value:filterText, setProps, debounce: true}),
        React.createElement('button', {onClick:buttonOnApply}, 'Apply'),
        React.createElement('button', {onClick:buttonOnRemove}, 'Remove Filter'),
    ]
  )

});

```

This uses the input’s `debounce` prop to keep from rendering each time you type. Removing the filter button works.

Also, a slight modification to your setProps → `setProps = ({value})` this means that we are only listening for the value object, and anytime this is updated, we would apply it, including blank strings (this registers false when testing for values).

[Next page](https://community.plotly.com/t/ag-grid-custom-filtering/79061.md?page=2)
