Filter in ag grid loses focus while typing

Hello @Brent,

This isnt an issue with the Grid, but an issue with the dcc.Loading.

The filter will update the model as you type, this issue would flash the loading screen each time you toggled a sort, if the grid was large enough. And would also be an issue for infinite scroll.

If you want to display a loading screen while a page is loading, you should check out my article here:

Having this level of flicker can indeed cause issues with an interface…

If you want to display a loading overlay while the data is loading to the grid, you can use the default loadingOverlay.

Just dont pass rowData to the grid when it is first loading:

from dash import callback, Dash, dcc, html, Input, no_update, Output
import dash_ag_grid as dag
import dash_bootstrap_components as dbc
import pandas as pd

app = Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP], suppress_callback_exceptions=True,
           meta_tags=[{'name': 'viewport', 'content': 'width=device-width, initial-scale=1.0'}])

dataframe = pd.DataFrame({'product_id': ['XYZ083-02ABC', 'NYZ082-02ABC', 'XYZ083-05ABC'],
                          'column_2_data': [2, 4, 6], 'column_3_data': [2, 4, 6], 'column_4_data': [2, 4, 6],
                          'column_5_data': [2, 4, 6], 'column_6_data': [2, 4, 6], 'column_7_data': [2, 4, 6],
                          'column_8_data': [2, 4, 6], 'column_9_data': [2, 4, 6], 'column_10_data': [2, 4, 6]})
default_col_def = {'filter': True,
                   'floatingFilter': True,
                   'resizable': True,
                   'sortable': True,
                   'editable': False,
                   'minWidth': 125,
                   'wrapHeaderText': True,
                   'autoHeaderHeight': True}

col_defs = [{'field': 'product_id', 'type' : None},
            {'field': 'column_2_data', 'type': 'numericColumn'},
            {'field': 'column_3_data', 'type': 'numericColumn'},
            {'field': 'column_4_data', 'type': 'numericColumn'},
            {'field': 'column_5_data', 'type': 'numericColumn'},
            {'field': 'column_6_data', 'type': 'numericColumn'},
            {'field': 'column_7_data', 'type': 'numericColumn'},
            {'field': 'column_8_data', 'type': 'numericColumn'},
            {'field': 'column_9_data', 'type': 'numericColumn'},
            {'field': 'column_10_data', 'type': 'numericColumn'}]

datatable = dag.AgGrid(id="datatable",
                       columnDefs=col_defs,
                       defaultColDef=default_col_def,
                       # rowData=dataframe.to_dict('records'),
                       dashGridOptions={'undoRedoCellEditing': True},
                       suppressDragLeaveHidesColumns=False,
                       persistence=True,
                       style={'resize': 'vertical', 'overflow': 'hidden'})

page = dcc.Loading(children=[dbc.Row(dbc.Col(html.Button(id="clear", n_clicks=0, children='Clear Filter', disabled=True),
                                             )),
                             dbc.ListGroup(children=[dbc.ListGroupItem(datatable)], flush=True)])

app.layout = dbc.Container(dbc.Card(dbc.CardBody(page)),
                           fluid=True)

@callback(Output("datatable", 'filterModel'),
          Input("clear", 'n_clicks'),
          prevent_initial_call=True)
def clear_filter(n_clicks):
    """Clear the filter query."""
    return {} if n_clicks else no_update

@callback(Output("clear", 'disabled'),
          Input("datatable", 'filterModel'),
          prevent_initial_call=True)
def enable_clear_filter(filter_query):
    """Enable/disable the clear filter button."""
    return filter_query == {}

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

You could even use some css magic with my loading screen trick from the topic and use a :has(.ag-overlay-loading-center to trigger your loading.

Here is an example with a 2 second fuse on the loading of the data:

from dash import callback, Dash, dcc, html, Input, no_update, Output
import dash_ag_grid as dag
import dash_bootstrap_components as dbc
import pandas as pd

app = Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP], suppress_callback_exceptions=True,
           meta_tags=[{'name': 'viewport', 'content': 'width=device-width, initial-scale=1.0'}])

dataframe = pd.DataFrame({'product_id': ['XYZ083-02ABC', 'NYZ082-02ABC', 'XYZ083-05ABC'],
                          'column_2_data': [2, 4, 6], 'column_3_data': [2, 4, 6], 'column_4_data': [2, 4, 6],
                          'column_5_data': [2, 4, 6], 'column_6_data': [2, 4, 6], 'column_7_data': [2, 4, 6],
                          'column_8_data': [2, 4, 6], 'column_9_data': [2, 4, 6], 'column_10_data': [2, 4, 6]})
default_col_def = {'filter': True,
                   'floatingFilter': True,
                   'resizable': True,
                   'sortable': True,
                   'editable': False,
                   'minWidth': 125,
                   'wrapHeaderText': True,
                   'autoHeaderHeight': True}

col_defs = [{'field': 'product_id', 'type' : None},
            {'field': 'column_2_data', 'type': 'numericColumn'},
            {'field': 'column_3_data', 'type': 'numericColumn'},
            {'field': 'column_4_data', 'type': 'numericColumn'},
            {'field': 'column_5_data', 'type': 'numericColumn'},
            {'field': 'column_6_data', 'type': 'numericColumn'},
            {'field': 'column_7_data', 'type': 'numericColumn'},
            {'field': 'column_8_data', 'type': 'numericColumn'},
            {'field': 'column_9_data', 'type': 'numericColumn'},
            {'field': 'column_10_data', 'type': 'numericColumn'}]

datatable = dag.AgGrid(id="datatable",
                       columnDefs=col_defs,
                       defaultColDef=default_col_def,
                       # rowData=dataframe.to_dict('records'),
                       dashGridOptions={'undoRedoCellEditing': True},
                       suppressDragLeaveHidesColumns=False,
                       persistence=True,
                       style={'resize': 'vertical', 'overflow': 'hidden'})

page = [dbc.Row(dbc.Col(html.Button(id="clear", n_clicks=0, children='Clear Filter', disabled=True),
                                             )),
                             dbc.ListGroup(children=[dbc.ListGroupItem(datatable)], flush=True)]

app.layout = dbc.Container(dbc.Card(dbc.CardBody(page)),
                           fluid=True)

@callback(Output("datatable", 'filterModel'),
          Input("clear", 'n_clicks'),
          prevent_initial_call=True)
def clear_filter(n_clicks):
    """Clear the filter query."""
    return {} if n_clicks else no_update

@callback(Output("clear", 'disabled'),
          Input("datatable", 'filterModel'),
          prevent_initial_call=True)
def enable_clear_filter(filter_query):
    """Enable/disable the clear filter button."""
    return filter_query == {}

@callback(Output('datatable', 'rowData'),
          Input('datatable','id'))
def firstLoad(id):
    import time
    time.sleep(2) # mimic long load
    return dataframe.to_dict('records')

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

To demonstrate this issue even further, try to maintain focus on this input:

from dash import callback, Dash, dcc, html, Input, Output
app = Dash(__name__)

app.layout = dcc.Loading([dcc.Input(id='testing', debounce=False), html.Div(id='output')])

@callback(Output('output', 'children'), Input('testing', 'value'))
def showValue(v):
    return v

if __name__ == '__main__':
    app.run_server(port=8850, debug=True)
1 Like