Persist AgGrid state across page changes

I have a multi-page Streamlit app with an AgGrid component on one page. I would like the state of the AgGrid to persist as I change pages (i.e., when I navigate back to its page it is exactly as I left it). Right now, when I navigate to a new page then back, it completely resets the AgGrid display. I want to persist column filter and sort as well as checkboxes selected for selection_mode="multiple". I see two options to solve this:

  1. Can I make Streamlit persist the AgGrid across pages? I can’t figure out when it re-renders the grid and then how to stop it from doing so. (I tested with multiple tabs on the same page and it works, i.e., grid does not reset when you change tabs.)

  2. Can I manually save AgGrid state and re-initialize it? GridOptionsBuilder.configure_selection seems to provide a solution for checkboxes using pre_selected_rows option but I don’t see a way to set column filters, only to set the properties of columns, like if its sortable, in GridOptionsBuilder.configure_default_column

# 00_home.py
import streamlit as st
st.write("Hello World")

# pages\01_aggrid_demo.py
import pandas as pd
from st_aggrid import GridOptionsBuilder, AgGrid, GridUpdateMode, DataReturnMode
from st_aggrid.shared import ColumnsAutoSizeMode

def display_grid(df: pd.DataFrame):    
    gb = GridOptionsBuilder.from_dataframe(df)
    gb.configure_selection(
        selection_mode="multiple",
        use_checkbox=True,
        pre_selected_rows=None,  # <-- Set to manually persist checkbox state
    )
    gridOptions = gb.build()
    AgGrid(
        df,
        gridOptions=gridOptions,
        update_mode=GridUpdateMode.GRID_CHANGED,
        columns_auto_size_mode=ColumnsAutoSizeMode.FIT_CONTENTS,
        data_return_mode=DataReturnMode.FILTERED   # <-- Gets filtered data, but not filters applied to columns
    )

# Dummy data
df = pd.util.testing.makeMixedDataFrame()
display_grid(df)

Hey @ngallo1,

Have you checked out these threads?

Yes. They only show how to maintain the row selection, not the column filtering

You can grab the state from the grid by using the AgGrid update_mode

  response = AgGrid(df,
           gridOptions=grid_options,
           height=600,
           width='100%',
           reload_data=True,
           update_mode = GridUpdateMode.MANUAL,
           data_return_mode=DataReturnMode.FILTERED_AND_SORTED,
           allow_unsafe_jscode=True,  # Set it to True to enable jsfunction
           )
    # Save grid state when user makes changes
    if response:
        if response.get('grid_state'):
            state = configure_grid_state(response['grid_options']['columnDefs'], response.get('grid_state') )

Then you can use a function like this to reassign the grid state:

def configure_grid_state(options, state):
    keys = (('aggregation', 'aggregationModel'), ('columnSizing', 'columnSizingModel'), ('sort', 'sortModel'))
    groups = state.get('rowGroup',{}).get('groupColIds',[])
    order = state.get('columnOrder',{}).get('orderedColIds',[])
    hidden = state.get('columnVisibility', {}).get('hiddenColIds', [])
    fields = {}
    for k in keys:
        if a:= state.get(k[0]):
            a = a[k[1]]
            for c in a:
                col = c.pop('colId')
                try:
                    fields[col].update(c)
                except KeyError:
                    fields[col] = c

    for c in options:
        c['sort'] = ''
        if c['field'] in fields:
            c.update(fields[c['field']])
            if order:
                c['order'] = order.index(c['field'])
        if c['field'] in groups:
            c['rowGroup'] = True
        else:
            c['rowGroup'] = False
        if c['field'] in hidden:
            c['hide'] = True
        else:
            c['hide'] = False
    return options

And then check if your state exists (like saved in a file or database) and recall using this:

    if state:
        for c in state:
            gb.configure_column(headerName= c.get('headerName', c.get('field')), field=c['field'], type= c['type'], filter= c.get('filter',''), aggFunc=c.get('aggFunc',''), sort=c.get('sort') , enableRowGroup=c.get('enableRowGroup', False), rowGroup=c.get('rowGroup', False), order=c.get('order',''), hide=c.get('hide', False))