St.experimental_set_query_params inconsistent?

Summary

This is a copy of Bad behavior with set_query_params · Issue #6907 · streamlit/streamlit · GitHub , but maybe the community can answer as well.

st.experimental_set_query_params does not always write its value to the browser.
In the following example, the write will fail exactly every other time - the new selection will be discarded every 2nd selection.

Has anyone seen this behavior? Any workarounds?

Steps to reproduce

Code snippet:

from typing import List, Any

import streamlit as st


def selectbox_with_query_storage(label: str, options: List[Any], query_param_name: str, **kwargs):
    default_index = 0
    current_query_params = st.experimental_get_query_params()
    current_value_params = current_query_params.get(query_param_name, [])
    current_value = None
    if len(current_value_params) == 1:
        current_value_str = current_value_params[0]
        current_value = type(options[0])(current_value_str)  # Convert to type based on first option.
        try:
            default_index = options.index(current_value)
        except ValueError:
            pass
    value = st.selectbox(label, options, index=default_index, **kwargs)
    if value != current_value:
        current_query_params[query_param_name] = value
        st.experimental_set_query_params(**current_query_params)
    return value


val = selectbox_with_query_storage("Remember me", ["a", "b", "c", "d", "e"], query_param_name="choice")
st.write(val)

https://noamgat-streamlit-example-streamlit-app-x1gje6.streamlit.app/

If applicable, please provide the steps we should take to reproduce the error or specified behavior.

Actual behavior:

  1. Select a value in the dropdown. The value and url will be updated.
  2. Select a value in the dropdown. The value and url will NOT be updated.
  3. Select a value in the dropdown. The value and url will be updated.
  4. Select a value in the dropdown. The value and url will NOT be updated.

Debug info

  • Streamlit version: Latest
  • Python version: 3.11
  • Operating System: Windows 11
  • Browser: Chrome
  • Virtual environment: Conda

Links

Additional information

1 Like

The issue was fixed:

I was able to workaround the bug, writing the solution here in case anyone finds it in the future.
The problem was, that if the index=___ parameter is passed to selectbox() , it is part of the ID. So if the index changes throughout the lifecycle of the app, the widget becomes a different one and the state breaks. The solution was to inject the default value not through the index=___ parameter, but through the session state. Fixed code below:

def selectbox_with_query_storage(label: str, options: List[Any], query_param_name: str, **kwargs):
    key = kwargs.pop("key", f"selectbox_with_query_storage_{query_param_name}")
    has_value_from_previous_renders = key in st.session_state

    current_query_params = st.experimental_get_query_params()
    current_value_params = current_query_params.get(query_param_name, [])
    query_value = None
    if len(current_value_params) == 1:
        query_value_str = current_value_params[0]
        query_value = type(options[0])(query_value_str)  # Deduce type from first option and convert.
    # There are two ways to set a preselected value in a selectbox - using the session state and the index=___ param.
    # The index=___ method causes problems if the index changes during the run, so we opt for the session state.
    # https://discuss.streamlit.io/t/set-selectbox-value/18376/4
    if query_value and not has_value_from_previous_renders:
        st.session_state[key] = query_value
    value = st.selectbox(label, options, key=key, **kwargs)
    if value != query_value:
        current_query_params[query_param_name] = value
        st.experimental_set_query_params(**current_query_params)
    return value
1 Like

Hi @noamgat

Thanks for sharing the question and solution for this use case.

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.