How to get a call back function with aggrid (similar to on_change with data_editor)?

Hi all!

I have this app that uses beautiful aggrid tables. Now I want to add new tables that, when a value is added, will call a function:


def edit_session_state(df, country, LEFT_RIGHT):
    st.session_state[f"manual_inputs_{country}_{LEFT_RIGHT}"]= df


editable_df = st.data_editor(manual_inputs_df, use_container_width=True, key=f"{country}_{LEFT_RIGHT}",
                                 on_change=edit_session_state, args=[manual_inputs_df,country, LEFT_RIGHT])

I’m calling the edit_session_state otherwise the input values will disappear (its a limitation of the session state: when I am calling it over various streamlit tabs, it will respond with a lag. Calling this function fixes this lag, as you can see in this example here: streamlit example )

However, for important visual reasons, I do not wish to use st.data_editor but use aggrid instead:

def produce_live_inputs_table(df, key, country, LEFT_RIGHT):
    column_defs = [
        {"field": 'contract', "headerName": 'contract', "minWidth": 160, "maxWidth": 170},
        {"field": "input", "headerName": "input", "precision": 2, "type": ["numericColumn"], "editable": True,
          "minWidth": 120, "maxWidth": 130},
        {"field": 'Mat', "headerName": 'Mat', "minWidth": 160, "maxWidth": 170}
    ]

    grid_options = {
        "columnDefs": column_defs,
        "suppressFieldDotNotation": True,
        "cellPadding": 0.5,
        "headerPadding": 0.5,
        "columnMenu": "new",
        "rowBuffer": 10,
        "enableRangeSelection": 'true',
        'editable': 'true'
    }

    gb = GridOptionsBuilder.from_dataframe(df)
    gb.configure_default_column(editable=True)
    gridOptions = gb.build()
    gridOptions.update(grid_options)

    grid_return = AgGrid(df, gridOptions=gridOptions, editable=True, data_return_mode=DataReturnMode.AS_INPUT,
                         update_mode=GridUpdateMode.VALUE_CHANGED,reload_data=True,
                         allow_unsafe_jscode=True, enable_enterprise_modules=True, filter=True,
                         theme="material", tree_data=True, height=450,
                         key=key)

    df = grid_return['data']

    edit_session_state(df, country, LEFT_RIGHT=LEFT_RIGHT)
    return df

editable_df = produce_live_inputs_table(manual_inputs_df, key=f"{country}_{LEFT_RIGHT}", country=country, LEFT_RIGHT=LEFT_RIGHT)

However, calling the function at the end of my produce_live_inputs_table function does not fix the issue as the callback in st.data_editor does.

Can someone help me mimic this callback effect?

Here is my entire code:

import streamlit as st
import pandas as pd

from st_aggrid import AgGrid, JsCode, GridUpdateMode, GridOptionsBuilder, DataReturnMode

st.button('Refresh')


tab_CH, tab_US, tab_EU = st.tabs(
    ["CHINA", "US", "EUROPE"])

country_tabs_dict = {
    "DE": tab_CH,
    "FR": tab_US,
    "BE": tab_EU,
}

def produce_live_inputs_table(df, key, country, LEFT_RIGHT):
    column_defs = [
        {"field": 'contract', "headerName": 'contract', "minWidth": 160, "maxWidth": 170},
        {"field": "input", "headerName": "input", "precision": 2, "type": ["numericColumn"], "editable": True,
          "minWidth": 120, "maxWidth": 130},
        {"field": 'Mat', "headerName": 'Mat', "minWidth": 160, "maxWidth": 170}
    ]

    grid_options = {
        "columnDefs": column_defs,
        "suppressFieldDotNotation": True,
        "cellPadding": 0.5,
        "headerPadding": 0.5,
        "columnMenu": "new",
        "rowBuffer": 10,
        "enableRangeSelection": 'true',
        'editable': 'true'
    }

    gb = GridOptionsBuilder.from_dataframe(df)
    gb.configure_default_column(editable=True)
    gridOptions = gb.build()
    gridOptions.update(grid_options)

    grid_return = AgGrid(df, gridOptions=gridOptions, editable=True, data_return_mode=DataReturnMode.AS_INPUT,
                         update_mode=GridUpdateMode.VALUE_CHANGED,reload_data=True,
                         allow_unsafe_jscode=True, enable_enterprise_modules=True, filter=True,
                         theme="material", tree_data=True, height=450,
                         key=key)

    df = grid_return['data']

    edit_session_state(df, country, LEFT_RIGHT=LEFT_RIGHT)
    return df

def edit_session_state(df, country, LEFT_RIGHT):
    st.session_state[f"manual_inputs_{country}_{LEFT_RIGHT}"]= df


def get_and_show_table(LEFT_RIGHT, country):
    if f"manual_inputs_{country}_{LEFT_RIGHT}" not in st.session_state:
        manual_inputs_dict = {
            "contract": ["Contract A", "Contract B", "Contract C", "Contract D"],
            "input": [100, 200, 150, 300],
            "Mat": ["2024-01-01", "2024-02-01", "2024-03-01", "2024-04-01"],
            }
        manual_inputs_df = pd.DataFrame(manual_inputs_dict)
        st.session_state[f"manual_inputs_{country}_{LEFT_RIGHT}"] = manual_inputs_df


    manual_inputs_df = st.session_state[f"manual_inputs_{country}_{LEFT_RIGHT}"]

    # Streamlit App
    st.title("Data Modification App")

    st.write("### Modify the DataFrame below:")


    # Use Streamlit's data editor to modify the DataFrame
    editable_df = st.data_editor(manual_inputs_df, use_container_width=True, key=f"{country}_{LEFT_RIGHT}",
                                 on_change=edit_session_state, args=[manual_inputs_df,country, LEFT_RIGHT])
    # editable_df = produce_live_inputs_table(manual_inputs_df, key=f"{country}_{LEFT_RIGHT}", country=country, LEFT_RIGHT=LEFT_RIGHT)

    st.write('editable_df')
    st.write(editable_df)




for country in country_tabs_dict.keys():
    with country_tabs_dict[country]:
        tab_LEFT, tab_RIGHT, tab_NONE = st.tabs([":zap: LEFT", ":sunny: RIGHT", ":waning_crescent_moon: NONE"])

        with tab_LEFT:
            get_and_show_table(LEFT_RIGHT='LEFT', country=country)

        with tab_RIGHT:
            get_and_show_table(LEFT_RIGHT='RIGHT', country=country)