Basically, once I click on a submit button, I want to create another submit button that does something if someone clicks on the following submit button. code below
if(st.button('Submit')):
text_outputs = get_sentences_associated_with_phrase(nl_query) # this returns a list
with st.form("my_form"):#, clear_on_submit=True):
for text_output in text_outputs:
clicked = st.checkbox(text_output) # this creates check boxes with what was in text_boxes
submitted = st.form_submit_button("Submit labels")
if submitted: # here is where I am stuck. This submit button doesn't work because it's nested
st.write(clicked)
As you can see, I nested the second submit button
if submitted: # here is where I am stuck. This submit button doesn't work because it's nested
st.write(clicked)
And if I click on that submit button, the desired action canât happen because itâs nested. Iâm not sure how to achieve this. any help would be greatly appreciated. Also, let me know if anything wasnât clear
Buttons wonât hold their states (they will only be true if they were the last thing touched). So if you want to nest things with buttons, you can create something else in session state to reference rather than the button values directly.
if 'stage' not in st.session_state:
st.session_state.stage = 0
def set_stage(stage):
st.session_state.stage = stage
# Some code
st.button('First Button', on_click=set_stage, args=(1,))
if st.session_state.stage > 0:
# Some code
st.button('Second Button', on_click=set_stage, args=(2,))
if st.session_state.stage > 1:
# More code, etc
st.button('Third Button', on_click=set_stage, args=(3,))
if st.session_state.stage > 2:
st.write('The end')
st.button('Reset', on_click=set_stage, args=(0,))
Checkboxes do have a state, so you could nest those just fine. (Though if you unchecked a parent, the children would be destroyed and wouldnât remember their previous state upon recreation.) Itâs just that with buttons, thereâs no persistent state so you have to rely on something else in session_state if youâre going to nest them.
Ok I think I understand that. What Iâm still stuck on is if I need to loop through a list, and create checkboxes with sentences in them. Example below
import streamlit as st
li = ['this is sentence 1', 'this is sentence 2']
with st.form("my_form"):
for sentence in li:
x = st.checkbox('good') # I know if make these different variables, this will work.
x = st.checkbox('bad') # but I can't do that because I'm looping
submitted = st.form_submit_button("Submit labels")
if submitted:
if some x was clicked:
st.write(the x values that were clicked)
Youâll need to assign keys to things in your form so you have access to the information and save Streamlit from getting confused about identical widgets.
I have an example of collecting user information from a list of pictures that you may find some inspiration from. This example doesnât use a form and collects the feedback into a dataframe with each user click.
Hereâs something with a form. I included something conditional on the submit button click directly, as well as provided a way to record the submit status persistently for comparison.
import streamlit as st
if 'submitted' not in st.session_state:
st.session_state.submitted = False
st.session_state
li = ['this is sentence 1', 'this is sentence 2']
def record_submitted():
st.session_state.submitted = True
def reset():
st.session_state.submitted = False
with st.form("my_form", clear_on_submit=True):
for i in range(len(li)):
st.write(li[i])
st.radio("Choose",['Good','Bad'],key=f'sentence{i}', horizontal=True)
submit = st.form_submit_button("Submit labels", on_click=record_submitted)
st.button('Do Nothing')
if submit:
st.write('The last thing clicked was the submit button.')
if st.session_state.submitted:
st.write('The last submission was:')
for i in range(len(li)):
st.write(f'{li[i]} : {st.session_state[f"sentence{i}"]}')
st.button('Reset',on_click=reset)
You can nest buttons, as long as you use something else along with them to track since they donât themselves keep their clicked state as you go along. The code I provided first can be nested. The conditionals are based on the âstageâ which is derived from the button clicks. You can indent subsequent conditionals and it will work fine. You can also record a separate state for each button individually if you want to.
if 'stage' not in st.session_state:
st.session_state.stage = 0
def set_stage(stage):
st.session_state.stage = stage
# Some code
st.button('First Button', on_click=set_stage, args=(1,))
if st.session_state.stage > 0:
# Some code
st.button('Second Button', on_click=set_stage, args=(2,))
if st.session_state.stage > 1:
# More code, etc
st.button('Third Button', on_click=set_stage, args=(3,))
if st.session_state.stage > 2:
st.write('The end')
st.button('Reset', on_click=set_stage, args=(0,))
Sorry, I donât think the above use case really solves what I am trying to do. Below is my code
clicked = {}
if 'stage' not in st.session_state:
st.session_state.stage = 0
def set_stage(stage):
st.session_state.stage = stage
li = ['this is sentence 1', 'this is sentence 2']
if(st.button('Submit', on_click=set_stage, args=(1,))):
with st.form("my_form"):#, clear_on_submit=True):
for e, text_output in enumerate(text_outputs):
clicked[e] = st.checkbox(text_output) # here I successfully create checkboxes with what's in the li list
submitted = st.form_submit_button("Submit labels") #I then create a submit button for this respective form. Note this submit button is the last thing being called
if st.session_state.stage == 1:
print('do something') # this works
if submitted: # this is where it fails because it doesn't recognize submitted
print('sub')
in the above example if submitted: # this is where it fails because it doesn't recognize submitted
I donât understand why submitted isnât recognized.
The page reloads when you interact with anything, so when you click the second submit button, the page reloads, you skip over that section of code that assigns a value to submitted (because it only shows immediately after a click on the first button), and thus submitted it is not recognized.
Not sure what you mean by that. If you store the data in session_state it will stay there for the whole session unless your code explicitly changes or deletes it.
This is exactly what my code is doing, yet when I print out st.session_state.clicked, it returns a dictionary with all the values set to False. Again I believe this is due to saving it inside of the st.session_state
I donât know what you mean by âthe value of being clickedâ either. When st.session_state.clicked[0] = st.checkbox("some text") is executed, the value of the checkbox is assigned to st.session_state.clicked[0].
To clarify, this does not happen when you click the widget but when the assignment is executed. You click the checkbox, its value changes, the application is rerun, st.checkbox(âsome textâ) will return the new value the next time it is executed.
There are ways to store widget values in session_state right after you interact with them, before the application is rerun, like specifying a key for the widget or using callbacks. Unfortunately I donât quite understand what you are tying to do here, so I am not sure how to adapt any of this to your use case.
if 'stage' not in st.session_state:
st.session_state.stage = 0
if 'clicked' not in st.session_state:
st.session_state.clicked = {}
def set_stage(stage):
st.session_state.stage = stage
if(st.button('Submit', on_click=set_stage, args=(1,))):
outputs, text_outputs = get_sentences_associated_with_phrase(nl_query) # this calls a function that receives a list of sentences, such as ['sentence 1', 'sentence 2'']
with st.form("my_form"):
for e, text_output in enumerate(text_outputs):
st.session_state.clicked[e] = st.checkbox(text_output) # st.session_state.clicked[e] is a dictionary holding the key with the value associated with it being true or false(clicked or not clicked)
submitted = st.form_submit_button("Submit labels", on_click=set_stage, args=(2,))
# I'll talk about the below code at the end
if st.session_state.stage == 2:
st.write(st.session_state.clicked)
So as the hashtags state, st.session_state.clicked[e] is a dictionary holding the key with the value associated with it being true or false(clicked or not clicked). So it should look like below if nothing is clicked
{
0 : False
1: False
}
or if the first sentence is clicked, if I print it out, it should look like
{
0 : True
1: False
}
but If I, for example click on one of the text boxes, and print it out using below code, it
if st.session_state.stage == 2:
st.write(st.session_state.clicked)
All of the values in the dictionary are always false, no matter which ones were clicked
Right. Inside a form it works in a different way. The widgets do not return the new values until the submit button is presed. But, in your case, neither the form nor the wigdets are there when the application reruns, so your dictionary is never assigned with the changed values.
One way to store the changed values is associating a unique key with each checkbox. Instead of assigning to clicked[e], use a key f"clicked_{e}".
At a minimum you also need to store the lenght of text_outputs so that later you know which keys you are interseted in. In my code I stored the whole list because I guess you want to use the strings in succesive reruns.
def set_stage(stage):
st.session_state.stage = stage
if "stage" not in st.session_state:
st.session_state.stage = 0
if(st.button('Submit', on_click=set_stage, args=(1,))):
st.session_state.text_outputs = ["sentences", "associated", "with", "phrase"]
with st.form("my_form"):
for e, text_output in enumerate(st.session_state.text_outputs):
st.checkbox(text_output, key=f"clicked_{e}")
submitted = st.form_submit_button("Submit labels", on_click=set_stage, args=(2,))
if st.session_state["stage"] == 2:
clicked = {
e: st.session_state[f"clicked_{e}"]
for e in range(len(st.session_state.text_outputs))
}
st.write(clicked)
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.