Can't get second st.form_submit_button to work?

Summary

I’m new to Streamlit and have a simple app first using a st.form and login in to a database and execute a query, the resultset should then be used as an input value list to the following form. However when I submit the second form it starts over from the beginning and shows the first form again. What I am doing wrong here? I’d like to iterate over the second form if/when it chnages but keep my login session./Thanks

Steps to reproduce

Code snippet:

#!/usr/bin/env python
import streamlit as st
import pandas as pd
import time

placeholder = st.empty()

with placeholder.form("Lgon form"):
    user = st.text_input("user")
    click = st.form_submit_button("Login")
    
if click:
    placeholder.empty()
    
    # here goes my login and sql query returning values in res0>
    # so far it's working - mimicken the returning dataframe
    
    values = pd.DataFrame(['A', 'B', 'C', 'D'], columns=['VALUE'])
   
    # creating the second form - contains a lot more params IRL
    with placeholder.form("Pick value"):
        val = st.selectbox('Value?',(values))
        run = st.form_submit_button("Run")
            
    if run:
        # code never reaches this section instead it starts over from top
        st.write("Here goes the rest of my code")
        time.sleep(5)

If applicable, please provide the steps we should take to reproduce the error or specified behavior.

Expected behavior:

See inline comments in code
Actual behavior:

Explain the undesired behavior or error you see when you run the code above.
If you’re seeing an error message, share the full contents of the error message here.

Debug info

  • Streamlit version: 1.16.0
  • Python version: 3.10.9
  • Using Conda? PipEnv? PyEnv? Pex?
  • OS version: MacOS
  • Browser version:

Requirements file

Using Conda? PipEnv? PyEnv? Pex? Share the contents of your requirements file here.
Not sure what a requirements file is? Check out this doc and add a requirements file to your app.

Links

  • Link to your GitHub repo:
  • Link to your deployed app:

Additional information

If needed, add any other context about the problem here.

1 Like

Hi @Mats_Johansson! Welcome to the community!

Ah yes…nested forms :slight_smile: it happens because you never enter the run==True condition. Let’s check what is happening (strategically placed st.session_state :slight_smile: checks):

import streamlit as st
import pandas as pd
import time

placeholder = st.empty()


with placeholder.form("Lgon form"):
    user = st.text_input("user")
    click = st.form_submit_button("Login")

st.session_state

if click:
    placeholder.empty()

    # here goes my login and sql query returning values in res0>
    # so far it's working - mimicken the returning dataframe

    values = pd.DataFrame(["A", "B", "C", "D"], columns=["VALUE"])
    st.session_state
    # creating the second form - contains a lot more params IRL
    with placeholder.form("Pick value"):
        val = st.selectbox("Value?", (values))
        run = st.form_submit_button("Run")

    if run:
        # code never reaches this section instead it starts over from top
        st.write("Here goes the rest of my code")
        time.sleep(5)

    st.session_state

App starts:

First submit:

second submit:

So…what to do? In general to save and share variables on reruns you can use st.session_state. Here is a great video from @andfanilo about nested buttons, using st.session_state and callbacks How to make NESTED buttons in Streamlit with Session State - YouTube

Working solution for your use case:

#!/usr/bin/env python
import streamlit as st
import pandas as pd
import time

placeholder = st.empty()


def callback():
    st.session_state["first_form_clicked"] = True


if "first_form_clicked" not in st.session_state:
    st.session_state["first_form_clicked"] = False


if not st.session_state["first_form_clicked"]:
    with placeholder.form("Lgon form"):
        st.session_state["user"] = st.text_input("user")
        st.form_submit_button("Login", on_click=callback)


if st.session_state["first_form_clicked"]:
    values = pd.DataFrame(["A", "B", "C", "D"], columns=["VALUE"])

    with placeholder.form("Pick value"):

        val = st.selectbox("Value?", (values))
        run = st.form_submit_button(
            "Run",
        )
        if run:
            # code never reaches this section instead it starts over from top
            st.write("Here goes the rest of my code")
            time.sleep(5)

Additional comment:

  • Also by definition, interdependent widgets within a form are unlikely to be particularly useful. If you pass the output of widget1 into the input for widget2 inside a form, then widget2 will only update to widget1’s value when the form is submitted.

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