Retain user selections after reload

Hi everyone

I am working on an app where the user can choose via a multiselect tool what months he wants to and via a drop down what customer he is interested in. However, whenever the page is refreshed, these selections are gone and he needs to choose everything again. I have come across the topic of session_state and callback but finding it impossibly difficult to understand. I have read quite a few articles, watched videos and tried out code but I just don’t get it. How can one store the user selections so they remain in place after a refresh?

Kind regards

Christoffer

Hi @Cenigk,

  1. Some widgets (like buttons) cause a streamlit refresh (re-running of code from the top)
  2. In such a scenario, if you have a variable:
    a. initially set to a certain value, and
    b. later change the variable value, and
    c. press the widget that causes a refresh
    your variable will again start with its initial defined value

If you want a variable to persist its value across refreshes, you need to define it as a session state variable by the statement:
if "my_variable_name" not in st.session_state: st.session_state.my_variable_name = "xyz"
This records the variable in the program’s session state and initializes it to the value ‘xyz’
Future changes to that variable in your code must be made by the statement: st.session_state.my_variable_name = "pqr"
Now the variable will have its last assigned value across refreshes (i.e pqr).


Callbacks are functions that can be associated with widgets. If a widget has a defined callback, then whenever the value of the widget is changed by the user, the callback is first called, to process whatever code is within it.

Hope that is understandable :slight_smile:

Hi Shawn, many thanks for getting back so quickly. I have prepared a very simple code that is I think in line with what you mean. However, I am missing something as it isn’t yet retaining the value when I press the reload button. This is the code:

import streamlit as st
from streamlit_js_eval import streamlit_js_eval

my_variable_name = st.sidebar.multiselect("Test", {'xyz','pqr'})

st.write(my_variable_name)

if st.button("Reload page"):
    streamlit_js_eval(js_expressions="parent.window.location.reload()")

if my_variable_name not in st.session_state:
    st.session_state.my_variable_name = 'pqr'

st.session_state.my_variable_name = 'xyz'

When I press the reload button, the multiselect is once again blank, rather than having the value that I last selected in it. So, if I select ‘pqr’ and then press the reload button, it goes back to being blank, rather than it showing the ‘pqr’ value. I have also tried to position the reload button code at the end, thinking it might have something to do with the cadence of the code but this changed nothing at all.

Sorry, I realise this must be quite elementary, trivial even - I hope it will become second nature one day.

KR

Christoffer

@Cenigk

If you’re pressing the browser reload button, it triggers a new session, so using session state is no good if that’s the case.

If that’s the case you would have to use a database technology such as MongoDB, Firestore or others to save the user’s selections, and fetch it everytime the user reloads the app.

2 Likes

Oh Gosh! I guess the issue is that we will have quite a lot of users that are interacting with the app, so it sounds quite complicated to need to save the variable to a database. The reason I have a reload button in my app is because once they input something in an editable grid, it then needs to rerun a relatively complex calculation in python. And unless the page is reloaded, it doesn’t seem to rerun that calculation. Is there another way of reloading without triggering a completely new session then?

Hi again. I have just realised something: rather than the button causing a reload and thus a complete new session, I could try and see if I can cause it to “re-run” instead. This might sound like the same thing, but it isn’t. I have tried out to cause the app to simply re-run and the script / calculation is still triggered but the it doesn’t create a sesion. So now the only question is, how do I cause a rerun rather than a reload

Ok, now I found the solution: If the button’s cause is just as per below:

if st.button(“Reload page”):
st.experimental_rerun()

then it only reruns the app, but doesn’t cause a new session. And all the user’s selection remain whilst still running the script and calculations.

In retrospect, the solution was so simple…well, I am just glad it worked

@Cenigk

Yes, that’s pretty much it. Remember you can also save lists on st.session_state if needed, such as:

import streamlit as st

# Define your options
options = ['A', 'B', 'C']

# Initialize selected options on your session state
if 'selected_options' not in st.session_state:
    st.session_state['selected_options'] = []
    
# The widget to select your options
selected_options = st.sidebar.multiselect("Test",
                                          options=options,
                                          default=st.session_state['selected_options'])

# Save the selected options on your session state
st.session_state['selected_options'] = selected_options

# Write the objects saved on your session state
st.write(st.session_state['selected_options'])

# Reload page
if st.button("Reload page"):
    st.rerun() # st.experimental_rerun() is not experimental anymore in latest Streamlit versions