I have a form that when I click the submit button I’d like a DB update to take place. I am using the session state to store the values needed for the DB update. Then in the callback I am accessing the session state to build and execute the update statement:
import streamlit as st;
def updateNotes():
notesUpdateSQL="UPDATE NOTES_TABLE SET NOTES=?,UPDATEDT=CURRENT_TIMESTAMP() WHERE USERID=?";
notesUpdateSQLArgs=[st.session_state.updatedNotes,st.session_state.currentUserId];
# Execute db operation here.
#Write args to see what would be sent.
#Always one click behind?
st.write(notesUpdateSQLArgs);
st.success("Notes Updated");
with st.form("notesForm"):
taNotes=st.text_area("Notes", value="");
currentUserId="123456"; #Simulated user ID
st.session_state.updatedNotes=taNotes;
st.session_state.currentUserId=currentUserId;
st.form_submit_button("Update Notes",on_click=updateNotes);
But I have noticed it is always “one click behind” what is in the text_area. I don’t know how else to put it.
For example, on a fresh run of the app, I type in “AAA” and see this after clicking:
Ok that seems to work in this instance, but I might have a use case in the future where I need multiple different inputs to be entered for a db operation. To prevent the app from rerunning after entering the first input, I would need to use a form.
Can you tell me if it is possible to do this with a form?
Don’t use a callback then. By the time the callback runs, the submitted values are not yet in session_state. I think this should work:
with st.form("notesForm"):
taNotes=st.text_area("Notes", value="")
currentUserId="123456"; #Simulated user ID
st.session_state.updatedNotes=taNotes
st.session_state.currentUserId=currentUserId
submitted = st.form_submit_button("Update Notes")
if submitted:
updateNotes()
You can do that in a form using keys and accessing them through the session state in the callback like this (the id can be passed as an argument since it isn’t defined by the user in an input):
import streamlit as st;
def updateNotes(UserId: int):
# get the session state here
updatedNotes = st.session_state.updatedNotes
notesUpdateSQL="UPDATE NOTES_TABLE SET NOTES=?,UPDATEDT=CURRENT_TIMESTAMP() WHERE USERID=?";
notesUpdateSQLArgs=[updatedNotes, UserId];
# Execute db operation here.
#Write args to see what would be sent.
#Always one click behind?
st.write(notesUpdateSQLArgs);
st.success("Notes Updated");
with st.form("notesForm"):
updatedNotes=st.text_area("Notes", value="", key=updatedNotes);
currentUserId="123456"; #Simulated user ID
st.form_submit_button("Update Notes", on_click=updateNotes, args=(currentUserId, ));
To explain why this doesn’t work for the sake of edification:
The script runs. toNotes has the default value of your text area. You then assign that default value to st.session_state.updatedNotes.
The user updates the text area. The script doesn’t rerun. The output is still the default value.
The user clicks the submit button.
The callback executes first. The value in st.session_state.updatedNotes is still the default value.
The app reruns.
Within the form, the widget now has the new output.
st.session_state.updatedNotes now has the new value (after the callback is already done).
The key point in @msquaredds’ answer is that a key is assigned to the widget within the form. When you click the submit button of a form, all the values of the widgets in Session State are updated first, then the callback runs, then the script runs which updates their output. You were one step behind because you were relying on the widget output to store the value in Session State instead of communicating with the widget directly through its key.
Thank you for the explanation. I am coming from the world of Java Swing into Streamlit. I am used to being able to get the updated value of a UI component after it has been interacted with while the program is running.
I guess what I need to remember is that the Streamlit app is not running when you are looking at it. Its really just a webpage, and things only “happen” during the rerun.
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.