How to disable a preceding widget using a button without clicking it twice?

Summary

I am trying to create a button that, when clicked, disables a text input that comes just before the button. Using session_state I can update the text input but I have to click twice unless the button comes before the text input or I click twice.

From what I can see Streamlit executes the re-run of the script but this time taking into account the button=True. Since it executes in order, my disabled session state variable only gets updated after the text box. I could try re-running the script again using experimental_rerun() but this seems a little clumsy.

Code:

import streamlit as st
from time import time

# Function to build input form
def build_input():
    # print current session state
    st.write(f"build_input() executed with st.session_state at {time()} with session_state=")
    st.session_state

    # try to access disabled value
    if "disabled" not in st.session_state:
        st.session_state.disabled = False
    
    st.write(f"session_state immediately before text_input=")
    st.session_state

    st.text_input(label="Input text here",
        disabled=st.session_state.disabled)

    if st.button(label="Disable input", key="launch"):
        st.session_state.disabled=True
        st.session_state.clicked_at=time()

# Interface
build_input()

st.session_state

Debug info

  • Deploying locally
  • Streamlit version: 1.11.0
  • Python version: 3.8.15
  • Using Conda
  • OS version: Mac OS
  • Browser version: Chrome Version 108.0.5359.124

Links

Hi @honytoad

Try out the following code and see if it works for you:

import streamlit as st

if "edflg" not in st.session_state:
    st.session_state.edflg = False

def btn_callbk():
    st.session_state.edflg = not st.session_state.edflg

def build_input():
    st.text_input(label="Input text here", disabled=st.session_state.edflg)

    if st.button(label="Enable input" if st.session_state.edflg else "Disable input", on_click=btn_callbk, key="launch"):
        st.session_state.disabled=True

build_input()

Cheers

1 Like

The callback does the job perfectly, thanks!

1 Like