✊🏿 Black Lives Matter. Please consider donating to Black Girls Code today.
⚡️ Concerned about the grid? Kyle Baranko teaches how to predicting peak loads using XGBoost. Register for the August webinar!

How to retain datatable filter after page refresh?

Hi there,

Currently, for dash_table filtering, once I refresh the page, the filter value is emptied.

I am looking for a way to retain data_table column filter value after refreshing page. What I am thinking is storing the filter value probably in dcc.Store and using that value to populate the filter later after page refresh.

Is there a way to achieve so using callback functions?

Thanks,
Meg

As best as I can tell the store is only available after the page loads, so you could easily have a “save filter” and “load filter” button or an interval that runs once and disables itself. Here’s an example of the latter:

import dash
import dash_core_components as dcc
import dash_html_components as html
from dash_table import DataTable


app = dash.Dash(__name__)

app.layout = html.Div([
    dcc.Interval(id='filter-load', interval=50),
    dcc.Store(id='filter-store', storage_type='local'),
    DataTable(
        id='dt',
        columns=[{
            'name': x,
            'id': x
        } for x in ['a', 'b', 'c', 'd']],
        export_format='xlsx',
        editable=True,
        filter_action='native',
        sort_action='native',
        data=[{
            'a': 'a' + str(x),
            'b': 'b' + str(x) + str(x),
            'c': 'c' + str(x) + 'c',
            'd': 'd' + str(x) + '-' + str(x)
        } for x in range(0, 100)]
    )
])


@app.callback(output=dash.dependencies.Output('filter-store', 'data'),
              inputs=[dash.dependencies.Input('dt', 'filter_query')])
def save_filter(filter_query):
    if filter_query is None:
        raise dash.exceptions.PreventUpdate
    return filter_query


@app.callback(output=[dash.dependencies.Output('dt', 'filter_query'),
                      dash.dependencies.Output('filter-load', 'disabled')],
              inputs=[dash.dependencies.Input('filter-load', 'n_intervals')],
              state=[dash.dependencies.State('filter-store', 'data')])
def load_filter(n_intervals, stored_filter):
    if n_intervals is None:
        raise dash.exceptions.PreventUpdate

    return stored_filter, True


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

Another option might to load the whole datatable as a callback this way, then you won’t have this second of seeing the unfiltered version of the table .

Building on this… Accessing Store data is somewhat difficult on load, but local/session storage IS accessible through JavaScript directly. Using clientside callbacks to access session / local storage data in order to populate the table’s filter parameter may be one way to go.

An untested example to give you an idea of what this would look like:

dash python app

...
app.clientside_callback(
    ClientsideFunction('myAppNamespace', 'preloadQuery'),
    Output('dt', 'filter_query'),
    [Input('filter-load', 'n_intervals')] 
)
""" note: you can use any Input as all callbacks are triggered on load """

in your assets folder create a javascript file with the following contents:

if (!window.dash_clientside) {
    window.dash_clientside = {};
}

let STORE = window.sessionStorage;
let TABLEQUERY_STORE_KEY = "table-query-filter";
let TABLEQUERY_DEFAULT = "LIMIT_TO_THIS_TEXT";

window.dash_clientside.myAppNamespace = {
    preloadQuery: function(trigger) {
        let query = STORE.getItem(TABLEQUERY_STORE_KEY);
        if (query == undefined) {
            query = JSON.stringify(TABLEQUERY_DEFAULT);
        }
        return query;
    },
}

The above doesn’t update session storage (you can use Damian’s example) but will grab from it if it exists.

1 Like

Well I’ve bookmarked this for future use!

Thanks for your solution. Inspired by the way you provided, I did find a way to retain the filter value and output the stored value in filter_query without using interval. The Store modified_timestamp should be triggered on the initial page load. When the modified_timestamp is triggered, the call back will take the stored value and use it for ‘filter_query’. Since the Store is in Session type, the value is only cleared when browser is closed.

1 Like

The value of filter_query can persist after refresh by adding persistence=True to the DataTable. See http://dash.plotly.com/persistence and http://dash.plotly.com/datatable/reference persisted_props.