Button inside st.expander to refresh only info in specific expander

Summary

I have multiple st.expanders and inside each one I want to have a button that will then rerun code thatā€™s related to that expander (without rerunning everything else), and then update the text written in the expander.

Iā€™ve tried using st.session_state in multiple ways to achieve this behavior, but I couldnā€™t figure out how to do it. I would appreciate your help!

Steps to reproduce

Code snippet:

import streamlit as st
from dataclasses import dataclass

@dataclass
class ExampleClass:
    name: str
    text: str

    def __int__(self, name, text):
        self.name = name
        self.text = text

    def edit_text(self):
        '''
        Runs external logic that modifies the self.text field
        '''
        self.text = self.text + ' modified text!'


def write_example_class(example_class: ExampleClass):
    st.subheader("Name:")
    st.write(f"{example_class.name}")
    st.subheader("Text:")
    st.write(f"{example_class.text}")


def create_streamlit_app():

    st.title("My title")

    if st.button("Run program"):
        # Here I have other code that creates two lists of ExampleClass
        # objects - relevant ones and not relevant ones.
        # For this example I just created the list of objects manually

        relevant_1 = ExampleClass('name1', 'relevant1')
        relevant_2 = ExampleClass('name2', 'relevant2')
        relevant_3 = ExampleClass('name3', 'relevant3')

        not_relevant_1 = ExampleClass('name1', 'not_relevant1')
        not_relevant_2 = ExampleClass('name2', 'not_relevant2')
        not_relevant_3 = ExampleClass('name3', 'not_relevant3')

        relevant_example_class = [relevant_1, relevant_2, relevant_3]
        not_relevant_example_class = [not_relevant_1, not_relevant_2, not_relevant_3]

        # continuation of real code
        st.header(f"Relevant examples ")

        for i, example_class in enumerate(relevant_example_class,
                                     start=1):
            expander_text = rf""" **{example_class.name}**"""

            example_class.edit_text() #run some code on the example_class
            # object which modifies the "text" field
            with st.expander(expander_text):
                write_example_class(example_class) # writes the modified text


        st.header(f"Not relevant examples:")

        for i, example_class in enumerate(not_relevant_example_class,
                                     start=1):
            expander_text = rf""" **{example_class.name}**"""
            with st.expander(expander_text):
                write_example_class(example_class)

                # here I want to give the user an option to run the
                # edit_text function on the not relevant examples
                if st.button('modify text', key=i):
                    example_class.edit_text()
                    write_example_class(example_class)

                    # but this here doesn't work, because when button is
                    # clicked, the script restarts from the beginning



if __name__ == '__main__':
    create_streamlit_app()

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

Expected behavior:

When the user clicks the button ā€œmodify textā€ inside the not_relevant_ expander, the text in the not_relevant_ expander will update to say ā€œnot_relevant modified text!ā€
For example, if the user clicks the ā€œmodify textā€ inside the not_relevant_1 expander, the text there will change to be ā€œnot_relevant1 modified text!ā€

Actual behavior:
When I click the ā€œmodify textā€ button, the entire page refreshes and brings me back to the original state where all I see is the title and the ā€œRun programā€ button.

Iā€™ve tried adding a session state variable to each button, but it doesnā€™t seem to work. What is the correct code design to use for getting this behavior?

Debug info

  • Streamlit version: 1.26.0
  • Python version: 3.11.5
  • Using pip
  • OS version: Windows
  • Browser version: Chrome

Requirements file

My requirements.txt file:
aiohttp~=3.8.5
tiktoken~=0.4.0
openai~=0.28.0
streamlit~=1.26.0
extract_msg==0.45.0

Thank you very much!

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