How to use forms with async

Hello! I am new to streamlit.
In the following code, I am unable to to change radio buttons and Accept Clips refreshes the entire page. There are multiple expanders which contains forms

Any clue, what am I missing?

import asyncio
import streamlit as st
from datetime import datetime, timedelta

from utils import load_s3_video
from src.utils.pushtomongo import video_to_clip_collection


st.set_page_config(
    page_title="View Clips",
    page_icon="📹",
    layout="wide",
)


sidebar = st.sidebar
content = st.container()

loop = asyncio.new_event_loop()
tasks = list()


async def load_and_display_video(item, col):
    with col:
        with st.spinner(f"Loading {item['title']}..."):
            video_bytes = await load_s3_video(item["s3_key"])
            col.video(video_bytes, format="video/mp4")


def display_form(document):
    _document_id = str(document["_id"])
    with st.form(_document_id):
        for col, item in zip(st.columns(len(document["clips"])), document["clips"]):
            for keys in ["title", "time", "duration"]:
                col.text(f"{keys.title()}:")
                col.code(item[keys])

        for col, item in zip(st.columns(len(document["clips"])), document["clips"]):
            _task = loop.create_task(load_and_display_video(item, col))
            tasks.append(_task)
            is_selected = col.radio(
                "Accept this video?",
                options=["Yes", "No"],
                index=0 if item["is_accepted"] else 1,
                key=_document_id + item["s3_key"],
            )

        st.markdown("---")
        if st.form_submit_button(label="Accept Clips"):
            print("Form Submitted")


def display_expander(document):
    with content.expander(document.get("title", document["video_id"])):
        cols = st.columns(2)

        cols[0].video(document["url"])
        for k, v in document.items():
            if type(v) != list:
                cols[1].text(f"{k.title()}:")
                cols[1].code(v)

        st.markdown("---")

        display_form(document)


def display_content(url: str, start_date, end_date):
    with content:
        st.title("📹 View Clips")
        for document in video_to_clip_collection.find(
            {
                "user_id": st.session_state.get("verified_username"),
                "$or": [
                    {"url": url},
                    {"video_id": url.split("/")[-1]},
                    {
                        "date": {
                            "$gte": datetime.combine(start_date, datetime.min.time()),
                            "$lte": datetime.combine(end_date, datetime.max.time()),
                        }
                    },
                ],
            },
        ):
            display_expander(document)


def display_sidebar():
    with sidebar:
        with st.form("search_view_clips_form"):
            url = st.text_input(
                "Enter the YouTube URL",
                key="url",
            )

            st.write("<b><center>(OR)</center></b>", unsafe_allow_html=True)

            start_date = st.date_input(
                "Start Date",
                key="start_date",
                value=datetime.now().date() - timedelta(days=1),
            )
            end_date = st.date_input(
                "End Date",
                key="end_date",
            )

            if st.form_submit_button(label="Load Clips"):
                display_content(
                    url=url,
                    start_date=start_date,
                    end_date=end_date,
                )

                loop.run_until_complete(asyncio.gather(*tasks))
                loop.close()


def main():
    display_sidebar()


if __name__ == "__main__":
    main()


hi @FromADistantLand
[It seems that the issue you’re facing is related to the behavior of the radio buttons and the page refresh when clicking the “Accept Clips” button.

Use unique keys for radio buttons: The key parameter in the radio method should be unique for each radio button to avoid conflicts. In your code, you’re using _document_id + item["s3_key"] as the key, but this might not be unique enough. You can try using a combination of both document ID and the item index for a more precise key.

is_selected = col.radio(
    "Accept this video?",
    options=["Yes", "No"],
    index=0 if item["is_accepted"] else 1,
    key=f"{_document_id}_{item['index']}",
)

  1. Use st.experimental_rerun to avoid page refresh:
if st.form_submit_button(label="Accept Clips"):
    print("Form Submitted")
    st.experimental_rerun()

@Dinesh_Jnld Thanks for the suggestion!
The app works as expected by using session_state and unique keys

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