I am displaying a large dynamic dataframe using streamlit and aggrid, with around 2000 rows and 20 columns. I am using pagination, sorting, and filtering to allow the user to get to relevant rows. The user can select multiple rows via checkboxes and click a "submit" button which gathers up the selected rows and sends a GET to another url based on what they've selected as query parameters.
The displaying, sorting, and pagination parts work great, but the checkbox selection part gets bogged down in handling the selection updates as the user selects multiple checkboxes (I've been using GridUpdateMode.SELECTION_CHANGED but have tried many things).
Ideally what I'd like is to use GridUpdateMode.NO_UPDATE and then 'grab' the selected rows when the user clicks a submit button. This would avoid the performance hit with every checkbox that is checked. The challenge is I'm not sure how to get at the selections doing this. I've tried using GPT and poking around in APIs with no luck. To illustrate the problem, here is a small example attempting both an on_click variant and checking the button state, neither have a grid_response (presumably because the server hasn't communicated the changes back to the server side):
import streamlit as st
from st_aggrid import AgGrid, GridUpdateMode, GridOptionsBuilder
import pandas as pd
# Sample data
data = {'col1': [1, 2, 3], 'col2': ['A', 'B', 'C']}
df = pd.DataFrame(data)
# Configure GridOptionsBuilder for row selection
gb = GridOptionsBuilder.from_dataframe(df)
gb.configure_selection(selection_mode='multiple', use_checkbox=True)
gridOptions = gb.build()
# Initialize AgGrid with NO_UPDATE mode
grid_response = AgGrid(
df,
gridOptions=gridOptions,
update_mode=GridUpdateMode.NO_UPDATE,
allow_unsafe_jscode=True,
key='gr1',
reload_data = True
)
def print_selected_rows():
selected_rows = grid_response['selected_rows']
st.write(selected_rows)
st.write(st.session_state.gr1)
st.write(grid_response.selected_data)
# Trigger to get selected rows
if st.button('Grab Selected Rows', on_click=print_selected_rows):
selected_rows = grid_response['selected_rows']
st.write(selected_rows)
st.write(st.session_state.gr1)
st.write(grid_response.selected_data)
I've tried some custom javascript things as suggested by GPT as well, but no luck so far. Also would be fine with a completely client side solution (gather up selections and call invoke URL), but again GPT has been fruitless so far.
In GridUpdateMode.NO_UPDATE
mode, the grid will not automatically update, so you will not have access to the updated data. However, you can still easily retrieve the selected rows on the frontend. To do this, you simply need to access the Ag-Grid API.
There are several ways to access the Grid API in the frontend. One approach is to hook into various Grid events and the AG Grid will pass the reference to the api
to the event callbacks.
Below I've given a approach where you can add your Grab Selected Rows button to the Grid Status bar. When you click this button, you’ll have access to the API
, and through it, you can retrieve the selected rows.
Code:
Selected rows will be printed in the browser console.
import streamlit as st
from st_aggrid import AgGrid, GridUpdateMode, GridOptionsBuilder, JsCode
import pandas as pd
# Sample data
data = {'col1': [1, 2, 3], 'col2': ['A', 'B', 'C']}
df = pd.DataFrame(data)
statusPanel = JsCode("""
class StatusBarComponent {
params;
eButton;
buttonListener;
init(params) {
this.params = params;
this.eButton = document.createElement('button');
this.buttonListener = this.onButtonClicked.bind(this);
this.eButton.addEventListener('click', this.buttonListener);
this.eButton.textContent = 'Grab Selected Rows';
this.eButton.style.border = '1px solid rgba(49, 51, 63, 0.2)';
this.eButton.style.backgroundColor = 'rgb(255, 255, 255)';
this.eButton.style.padding = '0.25rem 0.75rem';
this.eButton.style.borderRadius = '0.5rem';
this.eButton.style.fontSize = '1rem';
}
getGui() {
return this.eButton;
}
destroy() {
this.eButton.removeEventListener('click', this.buttonListener);
}
onButtonClicked() {
// You will get the selected rows data here.
console.log(this.params.api.getSelectedRows());
}
}
""")
# Configure GridOptionsBuilder for row selection
gb = GridOptionsBuilder.from_dataframe(df)
gb.configure_selection(selection_mode='multiple', use_checkbox=True)
statusBar = {
"statusPanels": [
{
"statusPanel": statusPanel,
"align": "left"
}
]
}
gb.configure_grid_options(statusBar=statusBar)
gridOptions = gb.build()
custom_css = {
".ag-root-wrapper": {"border": "0", "border-radius": "0"},
".ag-status-bar": {"position": "absolute", "width": "100%", "border-top": "0", "padding-left": "0"},
".ag-root-wrapper-body": {"margin-top": "40px", "border": "1px solid rgba(49, 51, 63, 0.15)", "border-radius": "2px"},
}
# Initialize AgGrid with NO_UPDATE mode
grid_response = AgGrid(
df,
gridOptions=gridOptions,
update_mode=GridUpdateMode.NO_UPDATE,
custom_css=custom_css,
allow_unsafe_jscode=True,
key='gr1',
reload_data = True
)