Hi @daviddemeij,
Though I am not sure if my proposed solution is the right solution for your issue, please let me elaborate the proposed workaround (I should have done that in the first place). I will be happy if this addresses your problem. Since majority of the code snippet given below uses a non-existent function, it is not a working code and therefore there could be minor errors. Otherwise please let me know.
Let us start with a code using a simple form:
import streamlit as st
def do_something(lower_threshold, upper_threshold):
#take action here
pass
lower_threshold = st.sidebar.text_input(label="Lower Threshold", value="0", key="na_lower")
upper_threshold = st.sidebar.text_input(label="Upper Threshold", value="100", key="na_upper")
st.sidebar.button(label="Submit", key="ta_submit")
do_something(lower_threshold, upper_threshold)
do_something() will be executed every time the value of an input widget is changed or a button is pressed – an undesirable situation which all of us are trying to avoid.
Now let us assume that we had a st function called get_last_used_widget_key() which returns the key of the widget last modified/pressed, perhaps an empty string in the first run. Let us now rewrite the relevant part of the code using the proposed function:
used_widget_key = st.get_last_used_widget_key()
lower_threshold = st.sidebar.text_input(label="Lower Threshold", value="0", key="na_lower")
upper_threshold = st.sidebar.text_input(label="Upper Threshold", value="100", key="na_upper")
st.sidebar.button(label="Submit", key="ta_submit")
if used_widget_key == "ta_submit":
do_something(lower_threshold, upper_threshold)
Now do_something() is executed only if the submit button was pressed.
We can extend this for multiple forms and therefore multiple submit buttons in the app. I can either check for each of the submit buttons as given below:
used_widget_key = st.get_last_used_widget_key()
#Form 1
st.sidebar.subheader("Form 1")
lower_threshold_1 = st.sidebar.text_input(label="Lower Threshold", value="0", key="na_lower_1")
upper_threshold_1 = st.sidebar.text_input(label="Upper Threshold", value="100", key="na_upper_1")
st.sidebar.button(label="Submit", key="ta_submit_1")
#Form 2
st.sidebar.subheader("Form 2")
lower_threshold_2 = st.sidebar.text_input(label="Lower Threshold", value="100", key="na_lower_2")
upper_threshold_2 = st.sidebar.text_input(label="Upper Threshold", value="200", key="na_upper_2")
st.sidebar.button(label="Submit", key="ta_submit_2")
if used_widget_key == "ta_submit_1":
do_something_1(lower_threshold_1, upper_threshold_1)
elif used_widget_key == "ta_submit_2":
do_something_2(lower_threshold_2, upper_threshold_2)
Or, if there are too many forms and therefore submit buttons, I can also write the last part differently if a naming convention is used for the key argument – here a prefix “ta_” for buttons:
if used_widget_key[0:3] == "ta_":
if used_widget_key == "ta_submit_1":
do_something_1(lower_threshold_1, upper_threshold_1)
elif used_widget_key == "ta_submit_2":
do_something_2(lower_threshold_2, upper_threshold_2)
The difference between the last two code snippets appear to be somewhat superfluous but in a large multi-page application, a good code structure is always welcome.
Looking forward to suggestions for improvement or if an alternative solution already exists.