How to maintain inputs on changing endpoints

Summary

Hello everyone, I am a beginner with streamlit and have created a basic multi page app. Now whenever I am changing the pages which are the endpoints, all the input data is lost. How can I have it in such a way that the input data remains even if I change pages.


This is the page where I am entering inputs. Now if I change the page.

And come back to the previous page.

All the input data is gone.
How can I avoid this to happen and the data stays even after changing pages.

This is my code:

Code snippet:

import streamlit as st

st.title('Haystack Editor')


with st.sidebar:
    numberq = st.number_input('Enter number of total Questions',min_value=0,step=1,key='numberq')

head1, head2 = st.columns([3,3])
if head1.button('Load'):
    head1.write('File Loaded')
else:
    pass

if head2.button('Save'):
    head2.write('File Saved')
else:
    pass

question = []
con = []
qno = []
ans = []
for i in range(numberq):
    con.append('')
    question.append('')
    ans.append('')
    qno.append(0)
for i in range(numberq):
    con[i] = st.container()
    qno[i] = con[i].number_input(str(i+1)+'. Add or remove Q&A',min_value=0,step=1)
    col1, col2 = con[i].columns([5, 5])
    que = []
    for j in range(qno[i]):
        que.append('')
    question[i] = que
    for j in range(qno[i]):
        question[i][j] = col1.text_input('Container '+str(i+1)+' Question '+str(j+1),label_visibility="visible" if j == 0 else "collapsed")

    ans[i] = col2.text_area('Container '+str(i+1)+' Answer',label_visibility="visible")

Debug info

  • Streamlit version: 1.14.0
  • Python version: 3.8.0
  • Using Conda

Thank you for your time.

You’ll need to use session_state to park your information while you navigate away from the page. Here’s a short example of committing some information from inputs into a dictionary within session_state.

I also made a little video recently about session_state: Session State Introduction

import streamlit as st

# Initialize on first page load so there is something to look up
if 'page1' not in st.session_state:
    st.session_state.page1 = {'A':'','B':0}

# A function to save information to session_state, bound to a submit button
def submit():
    st.session_state.page1 = {'A':st.session_state.page1A,
                              'B':st.session_state.page1B}

st.button('Submit', on_click=submit)

# Input widgets. Keys allow you to grab their saved info directly. Initial value grabbed from
# your designated save point in session_state allows them to re-render at your saved value
# when navigating back to the page
st.text_input('A', key='page1A', value = st.session_state.page1['A'])
st.number_input('B', key='page1B', value = st.session_state.page1['B'])
1 Like

Totally agree with @mathcatsand – you need to rely on session state rather than simply using lists.

Here’s a quick attempt to rewrite your app to explicitly store all of the questions in st.session_state. This seems to work after some brief testing, but you may need to tweak it.

import streamlit as st

st.title("Haystack Editor")

if "num_questions" not in st.session_state:
    st.session_state.num_questions = 0

if "questions" not in st.session_state:
    st.session_state.questions = {}

with st.sidebar:
    st.session_state.num_questions = st.number_input(
        "Enter number of total Questions",
        min_value=0,
        step=1,
        value=st.session_state.num_questions,
    )

head1, head2 = st.columns([3, 3])
if head1.button("Load"):
    head1.write("File Loaded")
else:
    pass

if head2.button("Save"):
    head2.write("File Saved")
else:
    pass

for i in range(st.session_state.num_questions):
    if i not in st.session_state.questions:
        st.session_state.questions[i] = {"qa_num": 1, "questions": {}, "ans": ""}

    question = st.session_state.questions[i]

    con = st.container()
    question["qa_num"] = con.number_input(
        str(i + 1) + ". Add or remove Q&A",
        min_value=0,
        step=1,
        value=question["qa_num"],
    )
    col1, col2 = con.columns([5, 5])
    for j in range(question["qa_num"]):
        if j not in question["questions"]:
            question["questions"][j] = ""

        question["questions"][j] = col1.text_input(
            "Container " + str(i + 1) + " Question " + str(j + 1),
            label_visibility="visible" if j == 0 else "collapsed",
            value=question["questions"][j],
        )

    question["ans"] = col2.text_input(
        "Container " + str(i + 1) + " Answer",
        label_visibility="visible",
        value=question["ans"],
    )

    st.session_state.questions[i] = question
1 Like

Thank you @mathcatsand, @blackary for the response. I am trying the code

@blackary The code is working but in the number input buttons there is a problem I need to click twice for plus or minus for some reason. Can you please help with this.

Hi @Devershi_Vashistha,

Yeah, I see that issue. I have a solution, but it involves a workaround that I’ll explain:

There’s a known bug with session state that is tied to widgets. when you switch pages (feel free to go to widget state not synced between multiple pages · Issue #4989 · streamlit/streamlit · GitHub and :+1: the issue if you would like), so it’s a bit more complicated because of that. But if you put these lines at the top of each page in your app, it fixes that issue, and you can make a simpler version of this page.

Put this on the top of each page:

for k, v in st.session_state.items():
    st.session_state[k] = v

Then this will work for that first page:

import streamlit as st

st.title("Haystack Editor")

if "num_questions" not in st.session_state:
    st.session_state.num_questions = 0

for k, v in st.session_state.items():
    st.session_state[k] = v

with st.sidebar:
    num_questions = st.number_input(
        "Enter number of total Questions",
        min_value=0,
        step=1,
        key="num_questions",
    )

head1, head2 = st.columns([3, 3])
if head1.button("Load"):
    head1.write("File Loaded")
else:
    pass

if head2.button("Save"):
    head2.write("File Saved")
else:
    pass

for i in range(num_questions):
    if f"qa_num_{i}" not in st.session_state:
        st.session_state[f"qa_num_{i}"] = 0

    if f"ans_{i}" not in st.session_state:
        st.session_state[f"ans_{i}"] = ""

    con = st.container()
    qa_num = con.number_input(
        str(i + 1) + ". Add or remove Q&A",
        min_value=0,
        step=1,
        key=f"qa_num_{i}",
    )
    col1, col2 = con.columns([5, 5])
    for j in range(qa_num):
        if f"question_{i}_{j}" not in st.session_state:
            st.session_state[f"question_{i}_{j}"] = ""

        col1.text_input(
            "Container " + str(i + 1) + " Question " + str(j + 1),
            label_visibility="visible" if j == 0 else "collapsed",
            key=f"question_{i}_{j}",
        )

    col2.text_input(
        "Container " + str(i + 1) + " Answer",
        label_visibility="visible",
        key=f"ans_{i}",
    )

Hi @blackary I tried the code but this one is not saving information on changing pages.

Hi @blackary @mathcatsand I am still unbale to save data on changing page without the buggy buttons which requires to click twice to change anything by them. Can you please help?

@Devershi_Vashistha Did you put this on the top of every page in your app?

Ok sorry, I only pasted the code on the first page but after putting on every page it is working. Thank you @blackary .