I’m trying to implement callback functions instead of clumsy workarounds like:
is_clicked = st.button()
if is_clicked:
[code here]
So I have a button with a callback function that alters session state keys:
def callback_func(arg):
st.session_state[arg] = arg_stuff
# Clear the session state Key1 for something not arg-related
st.session_state["Key1"] = []
def main():
df = pd.read_sql_query(sql,conn)
result = AgGrid(df,grid_options(df)) # Using AgGrid for single row select
st.button("Save to session state", on_click=callback_func(result))
Two things:
Clearing the session state key generates a StreamlitAPIException as follows:
StreamlitAPIException: st.session_state.Key1 cannot be modified after the widget with key Key1 is instantiated.
This error is generated when I make a selection in the AgGrid table, not when I click the button. In fact, the button doesn’t even render.
When I rerun the app leaving the AgGrid row selected, the screen refreshes with the same row selection and the same exception.
Major question: why is my callback function being executed before the button is being clicked? Even if I remove the exception-causing code, I can see the session state arg key being populated after AgGrid row selection without having me click the button first (to trigger the callback function).
(If someone wants to opine on the session state stuff, that’d be nice too, but maybe that’s for another thread. I want to clear an input widget based on this AgGrid table selection.)
Yes, you have correctly identified what I imagine is the bulk of the problem. on_click needs to receive a callable. If you put on_click=callback_func(result) then I believe callback(result) is going to execute when the associated widget it mounted (during the page load and before a user clicks the button). In general, args is computed when the widget is rendered, not when the widget is clicked. See the “Note” in this section.
As for args needing a tuple, it can accept a list also. However, if you want to pass a single value, even if it happens to be a list itself, put it in square brackets. The contents of the list or tuple passed to args are used in the callback function. In your case, even though result is a list already, it is the list itself as a single object that you are trying to pass:
args = [result]
With these corrections, do you still have a problem?
All is well, thanks! I might suggest that Streamlit throw an exception or error if someone assigns a malformed callable (with arguments) to on_click. It seems like it could be a common mistake.
Thanks for stopping by! We use cookies to help us understand how you interact with our website.
By clicking “Accept all”, you consent to our use of cookies. For more information, please see our privacy policy.
Cookie settings
Strictly necessary cookies
These cookies are necessary for the website to function and cannot be switched off. They are usually only set in response to actions made by you which amount to a request for services, such as setting your privacy preferences, logging in or filling in forms.
Performance cookies
These cookies allow us to count visits and traffic sources so we can measure and improve the performance of our site. They help us understand how visitors move around the site and which pages are most frequently visited.
Functional cookies
These cookies are used to record your choices and settings, maintain your preferences over time and recognize you when you return to our website. These cookies help us to personalize our content for you and remember your preferences.
Targeting cookies
These cookies may be deployed to our site by our advertising partners to build a profile of your interest and provide you with content that is relevant to you, including showing you relevant ads on other websites.