Widget on_change - Reset Text Input

Summary

Using a selectbox and text_input, how does one reset the text_input default value back to it’s original state if a different option within selectbox is chosen?

Steps to reproduce

  1. Run the code snippet below
  2. Change the text_input value from 5 to 10
  3. Change the selectbox from Project 1 to Project 2

Code snippet:

import streamlit as st

def on_text_input_change():
    current_input = st.session_state.change_input
    prev_input = st.session_state.prev_input
    if current_input != prev_input:
        del st.session_state['change_input']

def change_input(calc_default):
    default = st.text_input('Change Field', calc_default, key='change_input')
    return default

def choose_project():
    projects = st.selectbox('Project', ['Project 1', 'Project 2', 'Project 3'], key='project', on_change=on_text_input_change)
    return projects

calc_def = 5
st.session_state.prev_input = calc_def
choosen_project = choose_project()
input_text = change_input(calc_def)

for key, value in st.session_state.items():
    st.write(f"{key}: {value}")

Expected behavior:

The text_input defualt value changes back to default value when a new selectbox option is selected.

Actual behavior:

You can see the session state prev_input and change_input update as you alter the two widgets. Yet, when selectbox widget is updated, the text_input value does not change back to the default value.

Debug info

  • Streamlit version: 1.24.0
  • Python version: 3.10
  • Using Conda

Hey @Binx,
I made some changes on given code snippet.

import streamlit as st

def on_text_input_change():
    current_input = st.session_state.change_input
    prev_input = st.session_state.prev_input
    if current_input != prev_input:
        st.session_state.prev_input = current_input

def change_input(calc_default):
    default = st.text_input('Change Field', calc_default, key='change_input')
    return default

def choose_project():
    projects = st.selectbox('Project', ['Project 1', 'Project 2', 'Project 3'], key='project', on_change=on_text_input_change)
    return projects

calc_def = 5

if 'prev_input' not in st.session_state:
    st.session_state.prev_input = calc_def

choosen_project = choose_project()
input_text = change_input(st.session_state.prev_input)

for key, value in st.session_state.items():
    st.write(f"{key}: {value}")

When the code is run initially, it checks the prev_input is not in st.session_state. If not, initializes prev_input returns to its default value.
This script will slove your problem!:smiley:

Not sure if I was misleading in my question, but this does not solve my problem. Here is what I am looking for:

I don’t think del st.session_state['change_input'] is going to make streamlit forget the state of the textbox. You need to explicitly change the state to the desired value: st.session_state["change_input"] = calc_def.

Now you can only set the state of a textbox to a string. You can just set calc_def = "5" or if you really need the number, use str(calc_def).

Streamlit will complain with a warning because you are setting the textbox state both with the value parameter and using the key, so you better remove the value: st.text_input('Change Field', key='change_input').

By doing that you no longer have an initial value for the textbox, you can add st.session_state.setdefault("change_input", calc_default) right before instantiating the textbox.

The code after all those changes:

import streamlit as st


def on_text_input_change():
    current_input = st.session_state.change_input
    prev_input = st.session_state.prev_input
    if current_input != prev_input:
        st.session_state["change_input"] = calc_def


def change_input(calc_default):
    st.session_state.setdefault("change_input", calc_default)
    default = st.text_input("Change Field", key="change_input")
    return default


def choose_project():
    projects = st.selectbox(
        "Project",
        ["Project 1", "Project 2", "Project 3"],
        key="project",
        on_change=on_text_input_change,
    )
    return projects


calc_def = "5"
st.session_state.prev_input = calc_def
choosen_project = choose_project()
input_text = change_input(calc_def)

for key, value in st.session_state.items():
    st.write(f"{key}: {value}")

There is still room for improvement: on_text_input_change should be on_project_change and it should take the default value as a parameter, change_input is a weird name, st.session_state.prev_input is always equal to calc_def so it is not needed, etc. But it works as is.

1 Like

Yeah I ran into this warning a few times as I was troubleshooting. A colleague of mine did find a solution that works as well:

import streamlit as st


field_default = "5"

def change_input(calc_default):
    default = st.text_input('Change Field', calc_default, key='field_input')
    return default

def choose_project():
    projects = st.selectbox('Project', ['Project 1', 'Project 2', 'Project 3'], key='project', on_change=reset_field_input)
    return projects

def reset_field_input():
    st.session_state.field_input = field_default


choosen_project = choose_project()
input_text = change_input(field_default)

for key, value in st.session_state.items():
    st.write(f"{key}: {value}")

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