Iām developing a kind of survey using st.radio button inside a form. When I use the on_click function callback parameter of the submit button it always returns the default option and not the option that the user clicks.
Callback arguments are compiled at the moment their associated widget or button is rendered (not at the point they are called on click/change). I havenāt used exactly this configuration before, so unless there is some other issue with your data structure, my guess is that the self at the time the submit button is rendered is getting compiled into the callback function so you arenāt ever going to see new submission results.
You will need to assign keys to the widgets inside the form and then get their values from session state inside of the callback function instead.
This works for me:
import streamlit as st
class form_element():
def __init__(self, question, options, answer, key):
self.question = question
self.answer = answer
self.options = options
self.key = key
def check(self):
if st.session_state[self.key] == self.answer:
st.success('Correct!')
else:
st.error('Incorrect.')
def quiz(self):
with st.form(key='form'+self.key):
st.write(self.question)
st.radio('Answer',self.options, key = self.key)
st.form_submit_button('Submit', on_click=self.check)
my_form = form_element('Which comes first in the alphabet?', ['K', 'W', 'A', 'P'], 'A', 'question1')
my_form.quiz()
I actually realized that I wasnāt using a āst.session_stateā for the random function that randomizes the options. After organizing and cleaning up the code, I found a thread by Marisa_Smith explaining how to get around this and it worked! Iām cracking my head trying to understand the linear way Streamit works compared to pyQt which works in a loop/wait mode.
I really thought that the callback arguments were only called the moment the widget or button was clicked or changed. Thanks for explaining.
The callback functions are executed when clicked, yes, but at least for their arguments args I know for sure that their values are āpulledā at the point the widget loads. So if you had had some args=self.property than the lookup of that value would have happened when the button rendered and not seen a new value had it been changed in any way before the button was clicked.
This is a common confusion that comes up with forms. I was only taking a guess that there might have been some impact on the function via a similar construct since you were using self, but maybe that wasnāt the case. As I said, I had never tried structuring a form inside a class like that, so I just tried something I thought would work. Indeed, if you have some random generation and you want to continue to work with it, youād need to store the output into session state and make sure to not keep changing it with each page load. If fixing the random generation was all you needed, then great, the use of self didnāt actually throw an extra hiccup into the mix.