I am trying build a sharable streamlit app.
My idea is to capture user inputs from (selectbox, multiselectbox, toggle, checkbox etc.) from (top of) the page into URL and use URL back to restore the state.
But the issue here is with circular loop. Changing the selection value is changing the queryparams (on callback) and it inturn tries to update the default value and reruns the page immediately, without giving chance to user to pick more than one option in case of multiselect.
This is not an issue with other widgets which take only one input from user (selectbox, checkbox, toggle etc.), but multiselect suffers as now user can only pick one option at a time.
It also is probably rerunning the app for each input, which is bad.
Here is the relevant code to reproduce.
#! /usr/bin/env python3
import streamlit as st
def updateQueryParams(key):
'''
Update the query_params with the current session_state
'''
print(f'updateQueryParams: {key} {st.session_state[key]}')
if key in st.session_state and st.session_state[key] is not None:
st.query_params[key] = st.session_state[key]
else:
st.query_params.pop(key, None)
def addPlainMultiSelect(opts):
'''Add a plain multiselect'''
st.multiselect('Multiselect', opts, key='multiselect')
def addMultiSelectWithCallback(opts):
'''Add a multiselect with callback'''
key = 'multiselect2'
default = None
if key in st.query_params:
default = set(st.query_params.get_all(key)) & set(opts)
st.multiselect(
'MultiSelect With Callback',
opts,
default=default,
key=key,
on_change=updateQueryParams,
args=[key]
)
def test():
'''The main function'''
opts = [f'Val{i}' for i in range(10)]
addPlainMultiSelect(opts)
addMultiSelectWithCallback(opts)
if __name__ == '__main__':
test()
I am wondering if there is a better way to do this?
WHat I want is - callback should run after full user selection, when user clicks outside the dropdown or presses escape???