Open pwsanders7 opened 2 years ago
Hello @pwsanders7,
Actually the issue comes from Streamlit Elements. It is related to how I serialize DOM objects to JSON. Fortunately in your case, RadioGroup's onChange callback can still get the selected value with its second argument:
Signature:
function(event: React.ChangeEvent<HTMLInputElement>, value: string) => void
event: The event source of the callback. value: The value of the selected radio button. You can pull out the new value by accessingevent.target.value
(string).
Therefore, just changing sync()
arguments should fix your code.
# We don't want the first argument anymore (None).
# We want to sync the second argument with st.session_state.radio_value.
with mui.RadioGroup(name='RadioTest', defaultValue='Never', onChange=sync(None, 'radio_value')):
# ...
Regardless, this is an issue I'll address in an upcoming release.
That did the trick, thank you so much! This also worked for the slider, where I was having a similar issue, putting none for the first parameter solved it. Looking forward to working more fully with the library now!
On a related note, how would I handle this if I wanted to create a callback function instead of using sync? In the examples provided in the readme the callbacks all assume the single parameter of event, and I am note sure how to access the value prop this way.
Thank you again!
You can create a function with any number of parameter to match callback signatures.
In your case, you can replace sync(None, 'radio_value')
with:
def handle_change(event, value):
# event is not used
st.session_state.radio_value = value
# ...
with mui.RadioGroup(name='RadioTest', defaultValue='Never', onChange=handle_change):
# ...
But you're right, I'll add another callback example with more than one parameter.
Great thank you so much!
Hello again,
On a related note, can I add parameters that are not a part of the callback signature?
For example, I have a text field and I want to create a callback function, where I include a dynamic value for the key of the session state.
For example:
def text_to_response(event, state_variable):
st.session_state[state_var] = event.target.value
mui.TextField(label = label, onChange = text_to_response, multiline = multiline, fullWidth=fullWidth)
In this example, is there any way to add the state_variable argument in the mui.TextField? I have tried using the "props" argument but it does not work for me, and I have tried args.
Thank you again!
Hey @pwsanders7,
You can partially apply arguments to a function using functools's partial function. This is something I haven't documented yet because I'd like to find a better alternative, but in the meantime this does what you want.
from streamlit_elements import partial # or: from functools import partial
def text_to_response(event, state_var):
st.session_state[state_var] = event.target.value
mui.TextField(
label=label,
# This will apply state_var argument to text_to_response,
# resulting in a function that only takes an event parameter.
onChange=partial(text_to_response, state_var="my_var"),
multiline=multiline,
fullWidth=fullWidth
)
This is perfect thank you! I think this should cover my use case with no problem. I had recently done a small work around of using a lambda function and using setattr function on st.session_state. Your solution is much better as it will allow for more complex operations, thank you!
Thank you for creating such an amazing component, it is exactly what I had been hoping for. I have been playing around with it a bit and having difficulty accessing values from the event callbacks for the RadioGroup Below is my code for the radio group:
` with elements('RadioGroup'): if "radio_value" not in st.session_state: st.session_state.radio_value = None
When I do this, the "radio_value" attribute in session_state is equal to a dictionary with the following values: {'type': 'change', 'nativeEvent': {'isTrusted': True}, 'target': {'checked': True}, 'eventPhase': 3, 'bubbles': True, 'cancelable': True, 'timeStamp': 3176.4000000059605, 'defaultPrevented': False, 'isTrusted': True}
From this I would have expected to have gotten target.value, but there is only target.checked, which in this case is always true since something is checked.
It is highly possible this is an error in my code but curious if you had any input or if this is just one of the components that still has problems as you described in the Readme.