Ag-Grid editing behavior when using 'key' and 'reload_data'

Hi everyone,

I am trying the ag-grid component with a key (st.session_state.aggrid_key) and reload_data=True, to get the data to reload without redrawing (I want to avoid it disappearing for a fraction of a second). See my code below.

The button I am using works normally but after making an edit in ag-grid it stops working. Do you know why? Thanks in advance!

import pandas as pd
import streamlit as st
from st_aggrid import AgGrid, GridOptionsBuilder

st.title('Football goals for each player')

if 'aggrid_key' not in st.session_state:
    st.session_state.aggrid_key = True
    st.session_state.df = pd.DataFrame({'players':['A', 'B', 'C', 'D'], 'goals':[20, 23, 19, 41]})

st.markdown('When you load the app the button works normally')

if st.button('Add one goal to each player'):
    st.session_state.df['goals'] = st.session_state.df['goals'] + 1

gb = GridOptionsBuilder.from_dataframe(st.session_state.df)       
     
gb.configure_column(field='players',editable=False)

gb.configure_column(field='goals',editable=True)

gb.configure_grid_options(stopEditingWhenCellsLoseFocus=True,headerHeight=30,rowHeight=30)

go = gb.build()

st.markdown('But if later you edit the ag-grid, the button stops working')

ag = AgGrid(
    dataframe=st.session_state.df,
    key=st.session_state.aggrid_key,
    reload_data=True,
    height=180,
    gridOptions=go,
    enable_enterprise_modules=True)

if (st.session_state.df['goals'] != ag['data'].iloc[:,1]).any():
    st.session_state.df['goals'] = ag['data'].iloc[:,1].values
    st.experimental_rerun()

Hi there @thunderbug1,

Tagging you to ask if you know how to get around this one :slight_smile: Thanks in advance!

Hi there,
well sadly i don’t really have a solution here either.

to get the data to reload without redrawing (I want to avoid it disappearing for a fraction of a second)

I think the Agrid library itself does make this possible to change data with some javascript, but I am not sure if the react component does make it possible to do this from the python side of things.

The button I am using works normally but after making an edit in ag-grid it stops working. Do you know why?

I haven’t used the edit functionality myself yet, what exactly stops working?

1 Like

Thanks. With regards to what stops working:

  • The button modifies the input dataframe.

  • The final three lines of code ensure that, if user edits Ag-Grid, the input dataframe is modified too.

  • If user edits Ag-Grid, the button above stops working.

Maybe the issue is with my code’s structure or the last three lines of code?

Anyways, here is the same example but maybe easier to understand:

import pandas as pd
import streamlit as st
from st_aggrid import AgGrid, GridOptionsBuilder,GridUpdateMode,DataReturnMode

st.set_page_config(layout="wide")
st.title('Football goals for each player')
st.write('')

def add_goals():
    st.session_state.df['goals'] = st.session_state.df['goals'] + 1
    st.session_state.counter += 1

if 'aggrid_key' not in st.session_state:
    st.session_state.aggrid_key = 0
    st.session_state.counter = 0
    st.session_state.df = pd.DataFrame({'players':['A', 'B', 'C', 'D'], 'goals':[20, 23, 19, 41]})

col1,col2,col3,col4 = st.columns(4)
reload_data = False

with col1:
    st.markdown('When you load the app the button works normally:')
    bootoon = st.button('Add one goal to each player')
    if bootoon:
        add_goals()
        reload_data = True
    st.markdown('Count of times button was clicked:')
    st.write(st.session_state.counter)

with col2:
    st.markdown('Input dataframe before ag-grid:')
    st.dataframe(st.session_state.df)

with col3:
    st.markdown('But if later you edit the ag-grid, the button stops working')
    gb = GridOptionsBuilder.from_dataframe(st.session_state.df)
    gb.configure_column(field='players',editable=False)
    gb.configure_column(field='goals',editable=True)
    gb.configure_grid_options(stopEditingWhenCellsLoseFocus=True,headerHeight=30,rowHeight=30)
    go = gb.build()
    ag = AgGrid(
        dataframe=st.session_state.df,
        key=st.session_state.aggrid_key,
        reload_data=reload_data,
        height=180,
        gridOptions=go,
        enable_enterprise_modules=True)

with col4:
    st.markdown('Input dataframe after ag-grid:')
    st.dataframe(st.session_state.df)

if (st.session_state.df['goals'] != ag['data'].iloc[:,1]).any():
    st.session_state.df['goals'] = ag['data'].iloc[:,1].values
    st.experimental_rerun()

The only workarounds I found are either (a) changing the value of the key, or (b) not using a key at all, but both options make the Ag-Grid redraw and disappear for a fraction of a second, which is what I want to avoid that.

I am facing the same issue any solution yet?
When I set a key for aggrid function, grid does not update if i change the df externally ( other than using grid).
When I do not set key grid disappears for a short time after edit.

Unfortunately I am still looking for a solution to this too. :face_with_diagonal_mouth:

“When I do not set key grid disappears for a short time after edit.”
I am facing the same problem.
@PablocFonseca, is there any possible way to solve it?
Thank you very much!!

I’m working on a more intuitive way for this behaviour. In the past I used reload_data parameter to reload grid’s data without redrawing it. But I agree it is confusing.

1 Like

Thank you very much Pablo for this answer and for the great library you´ve made!

1 Like

I’ve updated the fixed key example to better explain how the key and reload_data parameters work:
https://share.streamlit.io/pablocfonseca/streamlit-aggrid/main/examples/example.py?example=Controling%20AgGrid%20redraw

let me know if its not clear enough.

2 Likes

This is a fantastic sample app! Thank you

Hi,

I required a re-render of the AgGrid table only after a button was clicked. To do this, I converted a datetime object into a string and used it as my unique key to regenerate a new version of the table.

If I have interpreted your question correctly, could you possibly set reload_data to False, capture any new changes and then call the grid_builder function (see below) to create another instance of AgGrid (similar to an auto reload).

I have added snippets of my code below - hopefully this helps:

# - - - - Function - - - - 

def grid_builder(grid_key: datetime, items: dict, cols_editable: list[str] = None) -> AgGrid:
    # without grid_key changing, the items from the db will not persist after initial render.
    grid_key = str(grid_key)
    df = pd.DataFrame(items)
    gd = GridOptionsBuilder.from_dataframe(df)
    gd.configure_pagination(enabled=True)
    gd.configure_default_column(groupable=True)
    if cols_editable != None:
        for col in cols_editable:
            gd.configure_column(field=col, editable=True)
    gd.configure_selection(selection_mode='multiple', use_checkbox=True)
    gridoptions = gd.build()

    grid_table = AgGrid(df, gridOptions=gridoptions,
                        update_on=['cellValueChanged'],
                        height=400,
                        theme='alpine',
                        key=grid_key)

    return grid_table


# - - - - Constants - - - - 

COLUMNS = ['a', 'b', 'c', 'd'] # made up column names


# - - - - Assign Session State Keys - - - - 

if 'grid_key' not in st.session_state:
    st.session_state['grid_key'] = datetime.now()
    
if 'project' not in st.session_state:
    st.session_state['project'] = None
    
    
# - - - - Logic - - - - 

project_selection = st.selectbox(
    label='Select Project Title', options=project_title_list)  # project_title_list is a list of titles from my db

if st.button(label='Load'):
    st.session_state['project'] = pd.DataFrame(db.fetch_all_items(
        project_selection), columns=COLUMNS) # db is from a separate python file that deals with firebase, where fetch_all_items takes a collection title
    st.session_state['grid_key'] = datetime.now()

grid = grid_builder(grid_key=st.session_state['grid_key'],
                    items=st.session_state['project'], cols_editable=COLUMNS[2:])```

@marduk did you find a solution for this issue? I have the same problem. Could you please help me?

1 Like

@PablocFonseca or anyone
Below grid is not reloading if I use key. Without key it is reloading if there is change in df. Only adding key,stoped grid reloading
Could you please help me?

            grid_response = AgGrid(
                df,
                gridOptions=grid_options,
                key="id_row",
                data_return_mode=DataReturnMode.AS_INPUT,
                update_mode=GridUpdateMode.MODEL_CHANGED,
                fit_columns_on_grid_load=False,
                enable_enterprise_modules=False,
                height=130,
                reload_data=False,
                allow_unsafe_jscode=True
            )
1 Like

Hello guys, I have a AgGrid table showing data from a real time metrics.
I want to reload data automatically every 15s. For this, I used st_autorefresh but the problem is the AgGrid (frontend) lost the selected rows after page update even using pre_selected_rows.
Do you know how to fix it?
A small piece of the code:

# ...
gb = GridOptionsBuilder.from_dataframe(df)
gb.configure_default_column(editable=True, wrapText=True, autoHeight=True)
gb.configure_column('ID', minWidth=80, maxWidth=80, type=["numericColumn","numberColumnFilter"], sortable=True, sort='desc', checkboxSelection=True, headerCheckboxSelection=True)
gb.configure_column('STATUS', minWidth=100, maxWidth=100)
gb.configure_pagination(paginationAutoPageSize=False, paginationPageSize=3)
gb.configure_side_bar()
gb.configure_selection('multiple', pre_selected_rows=st.session_state.pre_selected_rows, use_checkbox=True)
gb_grid_options = gb.build()
grid_return = AgGrid(
        df,
        gridOptions = gb_grid_options,
        key = 'ID',
        reload_data = True,
        data_return_mode = DataReturnMode.AS_INPUT,
        update_mode = GridUpdateMode.SELECTION_CHANGED or GridUpdateMode.VALUE_CHANGED or GridUpdateMode.MODEL_CHANGED,
        allow_unsafe_jscode = True,
        fit_columns_on_grid_load = False,
        enable_enterprise_modules = False,
        height = 320,
        width = '100%',
        theme = "streamlit"
    )
selected_rows = grid_return["selected_rows"]
for selected_row in selected_rows:
        pre_selected_rows.append(selected_row['_selectedRowNodeInfo']['nodeRowIndex'])
st.session_state.pre_selected_rows = pre_selected_rows
# ...
st_autorefresh(interval=((1*15*1000)), key="dataframerefresh")

This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.