Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Session State to Prepopulate Inputs #4831

Closed
ryantaylor406 opened this issue Jun 6, 2022 · 5 comments
Closed

Session State to Prepopulate Inputs #4831

ryantaylor406 opened this issue Jun 6, 2022 · 5 comments

Comments

@ryantaylor406
Copy link

Summary

I have a multipage app and I am trying to prepopulate the inputs on Page 1 with their previous input (if it exists) using st.session_state. The code I have written seemingly works at first (prepopulates the default value with their previous input) but when you go to change the value of the input, it seemingly deletes your entry and forces you to re-enter the value (works on the second attempt). I have tested this on text_input and multiselect but I imagine this happens with other inputs as well.

Steps to reproduce

Code snippet:

import streamlit as st   #1.6.0

def load_previous_input(label):
    """If it exists, populate input with previous user entry, otherwise None"""
    return st.session_state[label] if label in st.session_state else None

def save_input(label, new_value):
    """Overwrite previous input with new input"""
    st.session_state[label] = new_value

with st.sidebar:
    selected_page = st.radio('Select Page', ['Page 1', 'Page 2'])

if selected_page == 'Page 1':
    label = 'Enter Some Text'
    value = load_previous_input(label)
    user_text = st.text_input(label, value) if value is not None else st.text_input(label)
    save_input(label, user_text)

elif selected_page == 'Page 2':
    st.write("""Page 2: User does stuff on this page, when clicking back to Page 1, I want the field to
    prepopulate with what they entered before (if it exists). It seemingly works, (prepopulates with previous input)
    but look what happens when you try to change the text...
    """)

Expected behavior:

I expect to be able to change the value of the input without it getting erased and having to re-enter it a second time for it to stay.

Actual behavior:

First entry when trying to change the value is immediately erased, have to type input in a second time for it to stick.

Is this a regression?

Never attempted this before on previous versions.

Debug info

  • Streamlit version: 1.6.0
  • Python version: 3.10.2
  • Using Conda
  • OS version: Windows 10
  • Browser version: Chrome version 102.0.5005.63

Additional information

I am open to trying different ways of prepopulating inputs if anyone has done something similar before.

@ryantaylor406 ryantaylor406 added type:bug Something isn't working status:needs-triage Has not been triaged by the Streamlit team labels Jun 6, 2022
@sfc-gh-cfrasca
Copy link

Hi Ryan, thanks for flagging! I'm having trouble reproducing this locally. Here's a short video demonstrating how your code snippet behaves for me—is this different from what you're seeing? If so, can you please upgrade to the latest Streamlit release (1.10.0) and let me know if the behavior persists? Thanks!

@ryantaylor406
Copy link
Author

Hi Caroline,

It appears upgrading may have fixed the issue with the text input, however I am still having issues with the multiselect. I've attached the slightly modified code and a GIF showing what's happening on my end.

Thanks!

import streamlit as st

def load_previous_input(label):
    """If it exists, populate input with previous user entry, otherwise None"""
    return st.session_state[label] if label in st.session_state else None

def save_input(label, new_value):
    """Overwrite previous input with new input"""
    st.session_state[label] = new_value

with st.sidebar:
    selected_page = st.radio('Select Page', ['Page 1', 'Page 2'])

if selected_page == 'Page 1':
    label = 'Multiselect Field'
    value = load_previous_input(label)
    options = ['a','b','c']
    user_val = st.multiselect(label, options, value)
    save_input(label, user_val)

elif selected_page == 'Page 2':
    st.write("""Page 2: User does stuff on this page, when clicking back to Page 1, I want the field to
    prepopulate with what they entered before (if it exists). It seemingly works, (prepopulates with previous input)
    but look what happens when you try to change the selection...
    """)

upload_error · Streamlit - Google Chrome 2022-06-17 17-13-26

@carolinedfrasca carolinedfrasca removed type:bug Something isn't working status:needs-triage Has not been triaged by the Streamlit team labels Jun 22, 2022
@carolinedfrasca
Copy link
Collaborator

carolinedfrasca commented Jun 22, 2022

Hi @ryantaylor406, thanks for sharing that! The reason you're seeing this behavior is that when you change the value of the multiselect widget, the Streamlit app reruns (causing the value of the multiselect to revert to the value you had previously saved in session state). To avoid rerunning the app, you can use st.form to provide a submit button that users click after they've finished interacting with the multiselect widget. The app won't rerun until the user clicks that button. Here's an example (hosted here so you can try it out):

import streamlit as st

def load_previous_input(label):
    """If it exists, populate input with previous user entry, otherwise None"""
    return st.session_state[label] if label in st.session_state else None

def save_input(label, new_value):
    """Overwrite previous input with new input"""
    st.session_state[label] = new_value

with st.sidebar:
    selected_page = st.radio('Select Page', ['Page 1', 'Page 2'])

if selected_page == 'Page 1':
    with st.form("form"):
        label = 'Multiselect Field'
        value = load_previous_input(label)
        options = ['a','b','c']
        user_val = st.multiselect(label, options, value)
        submitted = st.form_submit_button("Submit")
        if submitted and user_val:
            save_input(label, user_val)

elif selected_page == 'Page 2':
    st.write("""Page 2: User does stuff on this page, when clicking back to Page 1, I want the field to
    prepopulate with what they entered before (if it exists). It seemingly works, (prepopulates with previous input)
    but look what happens when you try to change the selection...
    """)

@rajanant
Copy link

Hi @ryantaylor406, thanks for sharing that! The reason you're seeing this behavior is that when you change the value of the multiselect widget, the Streamlit app reruns (causing the value of the multiselect to revert to the value you had previously saved in session state). To avoid rerunning the app, you can use st.form to provide a submit button that users click after they've finished interacting with the multiselect widget. The app won't rerun until the user clicks that button. Here's an example (hosted here so you can try it out):

import streamlit as st

def load_previous_input(label):
    """If it exists, populate input with previous user entry, otherwise None"""
    return st.session_state[label] if label in st.session_state else None

def save_input(label, new_value):
    """Overwrite previous input with new input"""
    st.session_state[label] = new_value

with st.sidebar:
    selected_page = st.radio('Select Page', ['Page 1', 'Page 2'])

if selected_page == 'Page 1':
    with st.form("form"):
        label = 'Multiselect Field'
        value = load_previous_input(label)
        options = ['a','b','c']
        user_val = st.multiselect(label, options, value)
        submitted = st.form_submit_button("Submit")
        if submitted and user_val:
            save_input(label, user_val)

elif selected_page == 'Page 2':
    st.write("""Page 2: User does stuff on this page, when clicking back to Page 1, I want the field to
    prepopulate with what they entered before (if it exists). It seemingly works, (prepopulates with previous input)
    but look what happens when you try to change the selection...
    """)

I see same problem in your example with form.

Select one item first time - submit - all ok
select one more item - submit - currently selected item disappiared - left that was selected previously
select in third - submit - again everything ok
looks like it works on odds steps

@talentai
Copy link

You may want to try this new library. Solve my similar problem...https://github.com/PaleNeutron/streamlit-ext

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants