Capture and Save filter expression from Advanced Filters in Python Dash Ag-Grid

Hi, Guys!

I am using advanced filters on dash Ag-Grid by enabaling the enterprise components (as suggested on the link given below) and I am trying to capture and save the filter expression being written or built using the visual builder.

I am aware that with the column level filters, it is possibe to get the current state of filters using filterModel property of Ag-Grid. But, it does not return anything in this case of advanced filters.

Is there any other property or another way to do this? Basically, I want to save the filters to know what was the exact filter expression applied on the data and display the same on another output page to enable the users to reproduce the same output using the filter expression.

PFA the screenshots and my code file.

Looking forward to resolve this issue together, ASAP!

Advanced Filters Doc

Using column level filters with filterModel property

using advanced filters with filtermodel property

from dash import Dash, dcc, html, Input, Output, State
import pandas as pd
import dash_ag_grid
import dash_mantine_components as dmc

style_cell = {
    "fontFamily": "Inter",
    "fontSize": 14,
    "height": "30vh",
    "minWidth": "100%",
    "width": "100%",
    "maxWidth": "100%",
    "padding": "0.5rem",
    "textAlign": "center",
    "fontWeight": "normal",
}


data = {
    'Name': ['Alice', 'Bob', 'Charlie', 'David', 'Eva', 'Frank', 'Grace', 'Hannah', 'Ivy', 'Jack'],
    'City': ['New York', 'Los Angeles', 'Chicago', 'Houston', 'Phoenix', 'Philadelphia', 'San Antonio', 'San Diego', 'Dallas', 'San Jose'],
    'Age': [25, 30, 35, 40, 28, 32, 27, 45, 29, 31],
    'Gender': ['Female', 'Male', 'Male', 'Male', 'Female', 'Male', 'Female', 'Female', 'Female', 'Male'],
    'Salary': [70000, 80000, 120000, 90000, 75000, 85000, 95000, 105000, 60000, 78000]
}
df = pd.DataFrame(data)

grid = dash_ag_grid.AgGrid(
    id='ag-grid',
    columnDefs=[{"headerName": c, "field": c} for c in df.columns],
    rowData=df.to_dict("records"),
    className="ag-theme-balham color-setting",
    rowStyle={"defaultStyle": style_cell},
    dashGridOptions={
        "rowHeight": 25,
        "pagination": True,
        "paginationPageSize": 5,
        "icons": {
            "columnGroupOpened": '<i class="fa-regular fa-square-check"></i>',
            "columnGroupClosed": '<i class="fa-regular fa-square"></i>',
        },
        "domLayout": "autoHeight",
        "tooltipShowDelay": 100,
        "postSortRows": {"function": "postSort(params)"},
        "enableAdvancedFilter": True
    },
    enableEnterpriseModules=True,
    columnSize="sizeToFit",
    style={"height": "100%", "width": "100%"},
    defaultColDef={"editable": True, "filter": True, "floatingFilter": True, "filterParams": {"maxNumConditions": 6, "buttons": ["reset"], "closeOnApply": True}, "wrapText": True, "autoHeight": True, "cellStyle": {"wordBreak": "normal", "lineHeight": "unset"}},
)

app = Dash(__name__)

app.layout = html.Div([
    html.Div(id='filter-expression-display'),
    dmc.Space(h=30),
    grid,
])

# Add a callback to display the filter expression
@app.callback(
    Output('filter-expression-display', 'children'),
    Input('ag-grid', 'filterModel') # this property needs to be replaced with something similar for advanced filters
)
def display_filter_expression(data):
    print(data)
    if data:
        return f"Current Filter Expression: {data}"
    return "No filters applied."

if __name__ == '__main__':
    app.run_server(debug=True)

Hello @Shail-Shukla,

Welcome to the community!

Enjoy a full working example:

import dash_ag_grid as dag
from dash import Dash, html, dcc, Input, Output, State, no_update, Patch
import pandas as pd
import json

app = Dash(__name__)


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


columnDefs = [
    {"field": "athlete"},
    {"field": "age", "filter": "agNumberColumnFilter", "maxWidth": 100},
    {"field": "country"},
    {
        "headerName": "Date",
        "filter": "agDateColumnFilter",
        "valueGetter": {"function": "d3.timeParse('%d/%m/%Y')(params.data.date)"},
        "valueFormatter": {"function": "params.data.date"},
    },
    {"field": "sport"},
    {"field": "total"},
]

app.layout = html.Div(
    [
        dag.AgGrid(
             id="filter-options-example-simple",
            columnDefs=columnDefs,
            rowData=df.to_dict("records"),
            columnSize="sizeToFit",
            dashGridOptions={"animateRows": False, 'enableAdvancedFilter': True},
            enableEnterpriseModules=True,
            eventListeners={'filterChanged': ['myFilters(params, setGridProps, "gridFilters")']}
        ),
        dcc.Store(id='gridFilters'),
        html.Div(id='filters'),
        html.Button('store filter', id='storeFilter'),
        dcc.Store(id='storedFilters', data=[]),
        dcc.Dropdown(id='storedFilterSelection')
    ]
)

@app.callback(
    Output('filters', 'children'),
    Input('gridFilters', 'data')
)
def showFilters(d):
    if d:
        return json.dumps(d)
    return no_update

@app.callback(
    Output('storedFilters', 'data'),
    Input('storeFilter', 'n_clicks'),
    State('gridFilters', 'data'),
    prevent_initial_call=True
)
def saveFilter(n, d):
    if d:
        new = Patch()
        new.append({'label': f'{n}', 'value': json.dumps(d)})
        return new
    return no_update

@app.callback(
    Output('storedFilterSelection', 'options'),
    Input('storedFilters', 'data')
)
def updateOptions(d):
    if d:
        return d
    return no_update

app.clientside_callback(
    """(v, id) => {
        dash_ag_grid.getApi(id).setAdvancedFilterModel(JSON.parse(v))
        return dash_clientside.no_update
    }""",
    Output('filter-options-example-simple', 'id'),
    Input('storedFilterSelection', 'value'),
    State('filter-options-example-simple', 'id'),
    prevent_initial_call=True
)


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

---
var dagfuncs = window.dashAgGridFunctions = window.dashAgGridFunctions || {};

dagfuncs.myFilters = (params, setGridProps, id) => {
    if (params.source !== 'advancedFilter') return
    const data = params.api.getAdvancedFilterModel()
    dash_clientside.set_props(id, {data})
}

This uses a couple of new features like grid event listeners and also dash clientside set_props.

2 Likes

Hi, @jinnyzor!

Thanks for your response.

I could implement the same using Grid APIs.

Kindly take a look at my code as well and let me know your views.

from dash import dash, Dash, dcc, html, Input, Output, State, clientside_callback
import pandas as pd
import dash_ag_grid
import dash_mantine_components as dmc
import json

option_mapping = {
    "contains": "contains",
    "notContains": "does not contain",
    "startsWith": "begins with",
    "endsWith": "ends with",
    "blank": "is blank",
    "notBlank": "is not blank",
    "greaterThan": ">",
    "greaterThanOrEqual": ">=",
    "lessThan": "<",
    "lessThanOrEqual": "<=",
    "true": "is true",
    "false": "is false",
    "equals": {"text": "equals", "object": "equals", "number": "=", "date": "=", "dateString": "="},
    "notEqual": {"text": "not equal", "object": "not equal", "number": "!=", "date": "!=", "dateString": "!="},
}

def format_filter_expression(filter_dict):
    if "filterType" not in filter_dict:
        return ""

    filter_type = filter_dict.get("filterType")
    if filter_type == "join":
        join_type = filter_dict.get("type", "AND")
        conditions = filter_dict.get("conditions", [])
        formatted_conditions = [format_filter_expression(cond) for cond in conditions]
        return f"({f' {join_type} '.join(formatted_conditions)})"

    elif filter_type in ["text", "number"]:
        col_id = filter_dict.get("colId", "")
        filter_type_key = filter_dict.get("type", "")
        filter_value = filter_dict.get("filter", "")

        # Determine the data type
        data_type = "text"  # Default to "text" if not specified
        if filter_type == "number":
            data_type = "number"
        # Add more conditions if needed to infer data_type

        # Replace filter type using option_mapping
        if filter_type_key in option_mapping:
            filter_type = option_mapping[filter_type_key]
            if isinstance(filter_type, dict):
                filter_type = filter_type.get(data_type, filter_type.get("text"))  # Default to "text" if specific data type is not found
        else:
            filter_type = filter_type_key

        # Format filter value appropriately
        if data_type == "text":
            return f"[{col_id}] {filter_type} \"{filter_value}\""
        else:
            return f"[{col_id}] {filter_type} {filter_value}"

    else:
        return ""
    
    
style_cell = {
    "fontFamily": "Inter",
    "fontSize": 14,
    "height": "30vh",
    "minWidth": "100%",
    "width": "100%",
    "maxWidth": "100%",
    "padding": "0.5rem",
    "textAlign": "center",
    "fontWeight": "normal",
}



data = {
    'Name': ['Alice', 'Bob', 'Charlie', 'David', 'Eva', 'Frank', 'Grace', 'Hannah', 'Ivy', 'Jack'],
    'City': ['New York', 'Los Angeles', 'Chicago', 'Houston', 'Phoenix', 'Philadelphia', 'San Antonio', 'San Diego', 'Dallas', 'San Jose'],
    'Age': [25, 30, 35, 40, 28, 32, 27, 45, 29, 31],
    'Gender': ['Female', 'Male', 'Male', 'Male', 'Female', 'Male', 'Female', 'Female', 'Female', 'Male'],
    'Salary': [70000, 80000, 120000, 90000, 75000, 85000, 95000, 105000, 60000, 78000]
}
df = pd.DataFrame(data)

grid = dash_ag_grid.AgGrid(
    id='ag-grid',
    columnDefs=[{"headerName": c, "field": c} for c in df.columns],
    rowData=df.to_dict("records"),
    className="ag-theme-balham color-setting",
    rowStyle={"defaultStyle": style_cell},
    dashGridOptions={
        "rowHeight": 25,
        "pagination": True,
        "paginationPageSize": 5,
        "icons": {
            "columnGroupOpened": '<i class="fa-regular fa-square-check"></i>',
            "columnGroupClosed": '<i class="fa-regular fa-square"></i>',
        },
        "domLayout": "autoHeight",
        "tooltipShowDelay": 100,
        "postSortRows": {"function": "postSort(params)"},
        "enableAdvancedFilter": True
    },
    enableEnterpriseModules=True,
    columnSize="autoSize",
    style={"height": "100%", "width": "100%"},
    defaultColDef={"editable": True, "filter": True, "floatingFilter": True, "filterParams": {"maxNumConditions": 6, "buttons": ["reset"], "closeOnApply": True}, "wrapText": True, "autoHeight": True, "cellStyle": {"wordBreak": "normal", "lineHeight": "unset"}},
)

grid2 = dash_ag_grid.AgGrid(
    id='ag-grid2',
    columnDefs=[{"headerName": c, "field": c} for c in df.columns],
    rowData=df.to_dict("records"),
    className="ag-theme-balham color-setting",
    rowStyle={"defaultStyle": style_cell},
    dashGridOptions={
        "rowHeight": 25,
        "pagination": True,
        "paginationPageSize": 5,
        "icons": {
            "columnGroupOpened": '<i class="fa-regular fa-square-check"></i>',
            "columnGroupClosed": '<i class="fa-regular fa-square"></i>',
        },
        "domLayout": "autoHeight",
        "tooltipShowDelay": 100,
        "postSortRows": {"function": "postSort(params)"},
        "enableAdvancedFilter": True
    },
    enableEnterpriseModules=True,
    columnSize="sizeToFit",
    style={"height": "100%", "width": "100%", 'display':'none'},
    defaultColDef={"editable": True, "filter": True, "floatingFilter": True, "filterParams": {"maxNumConditions": 6, "buttons": ["reset"], "closeOnApply": True}, "wrapText": True, "autoHeight": True, "cellStyle": {"wordBreak": "normal", "lineHeight": "unset"}},
)


app = Dash(__name__)

app.layout = html.Div([
    html.Div(id='filter-expression-display'),
    dcc.Store(id='filter-expression-store', data=None),    
    dmc.Space(h=30), 
    grid,
    html.Div(id='filter-expression-display2'),
    dcc.Store(id='filter-expression-store2', data=None),    
    dmc.Space(h=30), 
    grid2
])


clientside_callback(
    """
    async (n1, n2, button) => {
        try {
            const gridApi1 = await dash_ag_grid.getApiAsync("ag-grid");
            const gridApi2 = await dash_ag_grid.getApiAsync("ag-grid2");

            if (!gridApi1 || !gridApi2) {
                console.error("Grid API not found or not initialized.");
                return [dash_clientside.no_update, dash_clientside.no_update];
            }
            
            // Get the current advanced filter model for grid 1
            const filterModel1 = gridApi1.getAdvancedFilterModel();
            // Get the current advanced filter model for grid 2
            const filterModel2 = gridApi2.getAdvancedFilterModel();

            // Convert the filter models to JSON strings for display
            const filterModelJson1 = JSON.stringify(filterModel1, null, 2);
            const filterModelJson2 = JSON.stringify(filterModel2, null, 2);

            return [filterModelJson1, filterModelJson2];
        } catch (error) {
            console.error("Error getting grid API or filter model:", error);
            return [dash_clientside.no_update, dash_clientside.no_update];
        }
    }
    """,
    Output('filter-expression-store', 'data'),
    Output('filter-expression-store2', 'data'),    
    Input("ag-grid", "virtualRowData"),
    Input("ag-grid2", "virtualRowData"), 
    
)

# Add a callback to display the filter expression
@app.callback(
    Output('filter-expression-display', 'children'),
    Input('filter-expression-store', 'data'),
)
def display_filter_expression(data):
    # print(data)
    if data:        
        return f"Current Filter Expression: {format_filter_expression(json.loads(data))}"
    return "No filters applied."



if __name__ == '__main__':
    app.run_server(debug=True)

Hello @Shail-Shukla,

While yes, this can work, you are listening to the virtualRowData which would also trigger any time that you are sorting, plus if you were to switch the an infinite row model, this would no longer work as the virtualRowData is dependent upon the clientside rowModel. (This would obviously be provided to the server as the filterModel in the request for rows, but still)

Plus, if these were to exist in modals, they would never work if the grid hasnt been rendered yet.

Here is an example that combines yours and mine:

from dash import dash, Dash, dcc, html, Input, Output, State, clientside_callback
import pandas as pd
import dash_ag_grid
import dash_mantine_components as dmc
import json

option_mapping = {
    "contains": "contains",
    "notContains": "does not contain",
    "startsWith": "begins with",
    "endsWith": "ends with",
    "blank": "is blank",
    "notBlank": "is not blank",
    "greaterThan": ">",
    "greaterThanOrEqual": ">=",
    "lessThan": "<",
    "lessThanOrEqual": "<=",
    "true": "is true",
    "false": "is false",
    "equals": {"text": "equals", "object": "equals", "number": "=", "date": "=", "dateString": "="},
    "notEqual": {"text": "not equal", "object": "not equal", "number": "!=", "date": "!=", "dateString": "!="},
}


def format_filter_expression(filter_dict):
    if "filterType" not in filter_dict:
        return ""

    filter_type = filter_dict.get("filterType")
    if filter_type == "join":
        join_type = filter_dict.get("type", "AND")
        conditions = filter_dict.get("conditions", [])
        formatted_conditions = [format_filter_expression(cond) for cond in conditions]
        return f"({f' {join_type} '.join(formatted_conditions)})"

    elif filter_type in ["text", "number"]:
        col_id = filter_dict.get("colId", "")
        filter_type_key = filter_dict.get("type", "")
        filter_value = filter_dict.get("filter", "")

        # Determine the data type
        data_type = "text"  # Default to "text" if not specified
        if filter_type == "number":
            data_type = "number"
        # Add more conditions if needed to infer data_type

        # Replace filter type using option_mapping
        if filter_type_key in option_mapping:
            filter_type = option_mapping[filter_type_key]
            if isinstance(filter_type, dict):
                filter_type = filter_type.get(data_type, filter_type.get(
                    "text"))  # Default to "text" if specific data type is not found
        else:
            filter_type = filter_type_key

        # Format filter value appropriately
        if data_type == "text":
            return f"[{col_id}] {filter_type} \"{filter_value}\""
        else:
            return f"[{col_id}] {filter_type} {filter_value}"

    else:
        return ""


style_cell = {
    "fontFamily": "Inter",
    "fontSize": 14,
    "height": "30vh",
    "minWidth": "100%",
    "width": "100%",
    "maxWidth": "100%",
    "padding": "0.5rem",
    "textAlign": "center",
    "fontWeight": "normal",
}

data = {
    'Name': ['Alice', 'Bob', 'Charlie', 'David', 'Eva', 'Frank', 'Grace', 'Hannah', 'Ivy', 'Jack'],
    'City': ['New York', 'Los Angeles', 'Chicago', 'Houston', 'Phoenix', 'Philadelphia', 'San Antonio', 'San Diego',
             'Dallas', 'San Jose'],
    'Age': [25, 30, 35, 40, 28, 32, 27, 45, 29, 31],
    'Gender': ['Female', 'Male', 'Male', 'Male', 'Female', 'Male', 'Female', 'Female', 'Female', 'Male'],
    'Salary': [70000, 80000, 120000, 90000, 75000, 85000, 95000, 105000, 60000, 78000]
}
df = pd.DataFrame(data)

grid = dash_ag_grid.AgGrid(
    id='ag-grid',
    columnDefs=[{"headerName": c, "field": c} for c in df.columns],
    rowData=df.to_dict("records"),
    className="ag-theme-balham color-setting",
    rowStyle={"defaultStyle": style_cell},
    dashGridOptions={
        "rowHeight": 25,
        "pagination": True,
        "paginationPageSize": 5,
        "icons": {
            "columnGroupOpened": '<i class="fa-regular fa-square-check"></i>',
            "columnGroupClosed": '<i class="fa-regular fa-square"></i>',
        },
        "domLayout": "autoHeight",
        "tooltipShowDelay": 100,
        # "postSortRows": {"function": "postSort(params)"},
        "enableAdvancedFilter": True
    },
    enableEnterpriseModules=True,
    columnSize="autoSize",
    style={"height": "100%", "width": "100%"},
    defaultColDef={"editable": True, "filter": True, "floatingFilter": True,
                   "filterParams": {"maxNumConditions": 6, "buttons": ["reset"], "closeOnApply": True},
                   "wrapText": True, "autoHeight": True, "cellStyle": {"wordBreak": "normal", "lineHeight": "unset"}},
    eventListeners={'filterChanged': ['myFilters(params, setGridProps, "filter-expression-store")']}
)

grid2 = dash_ag_grid.AgGrid(
    id='ag-grid2',
    columnDefs=[{"headerName": c, "field": c} for c in df.columns],
    rowData=df.to_dict("records"),
    className="ag-theme-balham color-setting",
    rowStyle={"defaultStyle": style_cell},
    dashGridOptions={
        "rowHeight": 25,
        "pagination": True,
        "paginationPageSize": 5,
        "icons": {
            "columnGroupOpened": '<i class="fa-regular fa-square-check"></i>',
            "columnGroupClosed": '<i class="fa-regular fa-square"></i>',
        },
        "domLayout": "autoHeight",
        "tooltipShowDelay": 100,
        # "postSortRows": {"function": "postSort(params)"},
        "enableAdvancedFilter": True
    },
    enableEnterpriseModules=True,
    columnSize="sizeToFit",
    style={"height": "100%", "width": "100%", 'display': 'none'},
    defaultColDef={"editable": True, "filter": True, "floatingFilter": True,
                   "filterParams": {"maxNumConditions": 6, "buttons": ["reset"], "closeOnApply": True},
                   "wrapText": True, "autoHeight": True, "cellStyle": {"wordBreak": "normal", "lineHeight": "unset"}},
    eventListeners={'filterChanged': ['myFilters(params, setGridProps, "filter-expression-store2")']}
)

app = Dash(__name__)

app.layout = html.Div([
    html.Div(id='filter-expression-display'),
    dcc.Store(id='filter-expression-store', data=None),
    dmc.Space(h=30),
    grid,
    html.Div(id='filter-expression-display2'),
    dcc.Store(id='filter-expression-store2', data=None),
    dmc.Space(h=30),
    grid2
])


# Add a callback to display the filter expression
@app.callback(
    Output('filter-expression-display', 'children'),
    Input('filter-expression-store', 'data'),
)
def display_filter_expression(data):
    # print(data)
    if data:
        return f"Current Filter Expression: {format_filter_expression(json.loads(data))}"
    return "No filters applied."


if __name__ == '__main__':
    app.run_server(debug=True)

js file:

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

dagfuncs.myFilters = (params, setGridProps, id) => {
    if (params.source !== 'advancedFilter') return
    const data = JSON.stringify(params.api.getAdvancedFilterModel() || {})
    dash_clientside.set_props(id, {data})
}

Hi @jinnyzor,

I tried the last code you sent but it is not working for me.

It is not capturing the filters being applied.

take a look at the screenshot and my code files.

assets\dashAgGridFunctions.js

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

dagfuncs.myFilters = (params, setGridProps, id) => {
    if (params.source !== 'advancedFilter') return
    const data = JSON.stringify(params.api.getAdvancedFilterModel() || {})
    dash_clientside.set_props(id, {data})
}
from dash import dash, Dash, dcc, html, Input, Output, State, clientside_callback
import pandas as pd
import dash_ag_grid
import dash_mantine_components as dmc
import json

option_mapping = {
    "contains": "contains",
    "notContains": "does not contain",
    "startsWith": "begins with",
    "endsWith": "ends with",
    "blank": "is blank",
    "notBlank": "is not blank",
    "greaterThan": ">",
    "greaterThanOrEqual": ">=",
    "lessThan": "<",
    "lessThanOrEqual": "<=",
    "true": "is true",
    "false": "is false",
    "equals": {"text": "equals", "object": "equals", "number": "=", "date": "=", "dateString": "="},
    "notEqual": {"text": "not equal", "object": "not equal", "number": "!=", "date": "!=", "dateString": "!="},
}


def format_filter_expression(filter_dict):
    if "filterType" not in filter_dict:
        return ""

    filter_type = filter_dict.get("filterType")
    if filter_type == "join":
        join_type = filter_dict.get("type", "AND")
        conditions = filter_dict.get("conditions", [])
        formatted_conditions = [format_filter_expression(cond) for cond in conditions]
        return f"({f' {join_type} '.join(formatted_conditions)})"

    elif filter_type in ["text", "number"]:
        col_id = filter_dict.get("colId", "")
        filter_type_key = filter_dict.get("type", "")
        filter_value = filter_dict.get("filter", "")

        # Determine the data type
        data_type = "text"  # Default to "text" if not specified
        if filter_type == "number":
            data_type = "number"
        # Add more conditions if needed to infer data_type

        # Replace filter type using option_mapping
        if filter_type_key in option_mapping:
            filter_type = option_mapping[filter_type_key]
            if isinstance(filter_type, dict):
                filter_type = filter_type.get(data_type, filter_type.get(
                    "text"))  # Default to "text" if specific data type is not found
        else:
            filter_type = filter_type_key

        # Format filter value appropriately
        if data_type == "text":
            return f"[{col_id}] {filter_type} \"{filter_value}\""
        else:
            return f"[{col_id}] {filter_type} {filter_value}"

    else:
        return ""


style_cell = {
    "fontFamily": "Inter",
    "fontSize": 14,
    "height": "30vh",
    "minWidth": "100%",
    "width": "100%",
    "maxWidth": "100%",
    "padding": "0.5rem",
    "textAlign": "center",
    "fontWeight": "normal",
}

data = {
    'Name': ['Alice', 'Bob', 'Charlie', 'David', 'Eva', 'Frank', 'Grace', 'Hannah', 'Ivy', 'Jack'],
    'City': ['New York', 'Los Angeles', 'Chicago', 'Houston', 'Phoenix', 'Philadelphia', 'San Antonio', 'San Diego',
             'Dallas', 'San Jose'],
    'Age': [25, 30, 35, 40, 28, 32, 27, 45, 29, 31],
    'Gender': ['Female', 'Male', 'Male', 'Male', 'Female', 'Male', 'Female', 'Female', 'Female', 'Male'],
    'Salary': [70000, 80000, 120000, 90000, 75000, 85000, 95000, 105000, 60000, 78000]
}
df = pd.DataFrame(data)

grid = dash_ag_grid.AgGrid(
    id='ag-grid',
    columnDefs=[{"headerName": c, "field": c} for c in df.columns],
    rowData=df.to_dict("records"),
    className="ag-theme-balham color-setting",
    rowStyle={"defaultStyle": style_cell},
    dashGridOptions={
        "rowHeight": 25,
        "pagination": True,
        "paginationPageSize": 5,
        "icons": {
            "columnGroupOpened": '<i class="fa-regular fa-square-check"></i>',
            "columnGroupClosed": '<i class="fa-regular fa-square"></i>',
        },
        "domLayout": "autoHeight",
        "tooltipShowDelay": 100,
        # "postSortRows": {"function": "postSort(params)"},
        "enableAdvancedFilter": True
    },
    enableEnterpriseModules=True,
    columnSize="autoSize",
    style={"height": "100%", "width": "100%"},
    defaultColDef={"editable": True, "filter": True, "floatingFilter": True,
                   "filterParams": {"maxNumConditions": 6, "buttons": ["reset"], "closeOnApply": True},
                   "wrapText": True, "autoHeight": True, "cellStyle": {"wordBreak": "normal", "lineHeight": "unset"}},
    eventListeners={'filterChanged': ['myFilters(params, setGridProps, "filter-expression-store")']}
)

grid2 = dash_ag_grid.AgGrid(
    id='ag-grid2',
    columnDefs=[{"headerName": c, "field": c} for c in df.columns],
    rowData=df.to_dict("records"),
    className="ag-theme-balham color-setting",
    rowStyle={"defaultStyle": style_cell},
    dashGridOptions={
        "rowHeight": 25,
        "pagination": True,
        "paginationPageSize": 5,
        "icons": {
            "columnGroupOpened": '<i class="fa-regular fa-square-check"></i>',
            "columnGroupClosed": '<i class="fa-regular fa-square"></i>',
        },
        "domLayout": "autoHeight",
        "tooltipShowDelay": 100,
        # "postSortRows": {"function": "postSort(params)"},
        "enableAdvancedFilter": True
    },
    enableEnterpriseModules=True,
    columnSize="sizeToFit",
    style={"height": "100%", "width": "100%", 'display': 'none'},
    defaultColDef={"editable": True, "filter": True, "floatingFilter": True,
                   "filterParams": {"maxNumConditions": 6, "buttons": ["reset"], "closeOnApply": True},
                   "wrapText": True, "autoHeight": True, "cellStyle": {"wordBreak": "normal", "lineHeight": "unset"}},
    eventListeners={'filterChanged': ['myFilters(params, setGridProps, "filter-expression-store2")']}
)

app = Dash(__name__)

app.layout = html.Div([
    html.Div(id='filter-expression-display'),
    dcc.Store(id='filter-expression-store', data=None),
    dmc.Space(h=30),
    grid,
    html.Div(id='filter-expression-display2'),
    dcc.Store(id='filter-expression-store2', data=None),
    dmc.Space(h=30),
    grid2
])


# Add a callback to display the filter expression
@app.callback(
    Output('filter-expression-display', 'children'),
    Input('filter-expression-store', 'data'),
)
def display_filter_expression(data):
    # print(data)
    if data:
        return f"Current Filter Expression: {format_filter_expression(json.loads(data))}"
    return "No filters applied."


if __name__ == '__main__':
    app.run_server(debug=True)

Are you using grid 31.2?

Had to upgrade Dash version to 2.17.0

It looks good.

Thanks, @jinnyzor ! Appreciate your help here.

1 Like

Ah.

set_props

Is a new feature of 2.16+ :grin: