FYI to all: You can upvote the feature request to add a “select all” button to st.multiselect.
Thanks @mathcatsand for the answer. I have modified your code slightly to include the if and else block in both “update checkbox” and “update_multiselect” function. My application sometimes take a few minutes to run and to simulate that I have use time.sleep() in the code below. The problem is when all three options have been selected in multiselect and if I remove two of those options quickly while the app is still running, then all the options get cleared out from the multiselect instead of just clearing out the two options that were removed. But if I do the same thing after commenting out the line that contains time.sleep(), then it works as expected. Could you let me know why Streamlit behaves differently in the two cases and how can I resolve this?
import streamlit as st
import time
# Initialize the vlue of both widgets through session state
if "multiselect_key" not in st.session_state:
st.session_state.multiselect_key = []
st.session_state.all = False
def update_checkbox():
if len(st.session_state.multiselect_key) == 3: # if all are selected
st.session_state.all = True # Force checkbox to True (and disable it)
else:
st.session_state.all = False
time.sleep(3) # Comment out this line to get different behavior
def update_multiselect():
if st.session_state.all:
st.session_state.multiselect_key = ["A", "B", "C"]
else:
st.session_state.multiselect_key = []
st.multiselect(
"Select items",
options=["A", "B", "C"],
key="multiselect_key",
on_change=update_checkbox,
placeholder="All"
)
st.checkbox("Select All", key="all", on_change=update_multiselect)
This doesn’t happen if you remove this. I think this is a bug.
If you go from all and remove two in succession, the first removal starts its callback quickly enough to set st.session_state.all=False. When you click the next one, the callback is still running, and because the checkbox value was changed in that incomplete run, Streamlit is registering a “change” to the checkbox and running the callback. Had the first run completed before removing the second option, Streamlit doesn’t get confused about a misread that the checkbox “changed” from the user.
The bug report exists here: on_change callback is triggered without user-interaction on in-script delays · Issue #10102 · streamlit/streamlit · GitHub
Thanks @mathcatsand for the clarification. I removed the else block and use the “disabled” parameter based on the value of st.session_state.all. This workaround is functioning well for now. Looking forward to this “Select All” feature being natively supported on Streamlit.