on_change not called for first session_state value
See original GitHub issueSummary
Streamlit 0.84 introduces an on_change
callback for some interactive widgets as part of the new Session State API. I’ve found that the callback is not invoked for the first value (i.e., the widget’s default or initial value), only for subsequent values.
Steps to reproduce
Code snippet:
import streamlit as st
def colour_changed():
st.info(f"colour_changed: {st.session_state.colour}")
colour = st.selectbox("Colour", ["blue", "red", "yellow", "green"], key="colour", on_change=colour_changed)
st.info(f"selectbox returned: {colour}")
- When the report is first run, the selectbox returns
blue
as the selected value, but thecolour_changed()
callback is not called. - When a different colour is selected, the selectbox returns the new colour and
colour_changed()
is called.
Expected behavior:
I believe the on_change
callback should be called when a widget sets the initial/default value.
I’m finding that the lack of a callback for the initial value greatly complicates things because I can’t depend on the callback to do stuff for every value of an interactive widget. I have to write special cases for the initial state.
This is further complicated by what seems like a bug initializing default session_state values for widgets like selectbox (see #3598).
Actual behavior:
The on_change
callback is not called for a widget’s initial/default value.
Is this a regression?
No. The Session State API is new in Streamlit 0.84.
Debug info
- Streamlit version: Streamlit, version 0.84.2
- Python version: Python 3.8.11
- Using Conda? PipEnv? PyEnv? Pex? Just pip
- OS version: Debian buster (in a python:3.8 container)
- Browser version: Safari 14.1 on macOS Mojave 10.14.6
Additional information
None.
Community voting on feature requests enables the Streamlit team to understand which features are most important to our users.
If you’d like the Streamlit team to prioritize this feature request, please use the 👍 (thumbs up emoji) reaction in response to the initial post.
Issue Analytics
- State:
- Created 2 years ago
- Comments:10 (3 by maintainers)
I would like to reiterate the request of @kinghuang,
I believe the on_change callback should be called when a widget sets the initial/default value.
I have several selectbox chained dynamically. If there appear only one option in one of those selectboxes, the rest won’t work because I am not able to call on_change function. I mean that on_change callback is not called by the selectbox with one option.Sure, I don’t have time to whip up a full example app right now, but I’ll try to describe the main bits.
I’m currently using Streamlit to build a series of review apps for our spaCy NLP pipelines. Using the new State API, I’ve been storing a database session object, a batch of rows for review, and a process object (basically a controller for what’s being reviewed). Central to the apps are custom Streamlit components for doing things like scoring the quality of the Doc objects or modifying labels in the entity spans in the Doc objects.
Here’s an abbreviated version of the function that is struggling with the
on_change
calls.When a
batch_info
is selected, I want to commit changes in the batch being edited (if any), then fetch the new batch of objects from the database for editing.If you look for the
# Workaround
comments, you can see where theon_change
functions are being explicitly invoked for both process and batch selection. Without them, the initial/default batch that is selected doesn’t load, for example, because the batch selectbox’son_change
function isn’t called.If I didn’t set the
key
attribute on the batch selector on the batch selectbox and relied on its return value, I would get the value (including the initial/default value) on every run of the code. But, then, I’d have to implement my own change detection, probably by storing a value insession_state
and then comparing it to the return value.