Refresh page and Reset checkbox after a button is clicked

Hi, I am learning how to use python/streamlit and making an app that stores data and this part where the user wants to delete all data is giving problems. here is the workflow:

  • user clicks on a checkbox to delete data
  • user clicks on button to confirm delete - i use a double confirm to ensure no one accidentally deletes all data
  • all data is deleted - the page should automatically refresh to show ‘no data’
  • The checkbox is reset to ‘unchecked’ so the user can come back here and delete data again if they reimport anything.

I know we can have an st.rerun() to automatically refresh if user deletes the data, but streamlit doesn’t recommend having a rerun inside a button condition. For a good reason too, I saw that if I use a rerun inside there, no matter what if/else condition i put it in, it always keeps refreshing the page. Problem is, without a rerun, I don’t see how I can refresh the page to show no data. If i don’t use it, it says all data cleared but still shows all the data in all pages. I have tried different variables, session_state variables, etc. but somehow it’s either one of the two problems.
Another problem I have seen is if I revert the checkbox to unchecked, it just doesn’t delete my data. The behavior I see is it clears out my data if I click on the button twice (even though the page doesn’t refresh and my table is still populated), and the second time it gives me this error: streamlit.errors.StreamlitAPIException: st.session_state.delAllCheck cannot be modified after the widget with key delAllCheck is instantiated.
The third time I click on the confirm delete button, it actually refreshes the page and the error goes away.

This is the part of main.py

        with col1:
            st.session_state.confirm_delete = st.checkbox("Delete all history", value=False, key="delAllCheck")
            butclick = st.button("Confirm")
            if butclick and st.session_state.get('confirm_delete', True):
                df = clear_all_history()
                #st.session_state.delAllCheck = False
                st.success("All history has been cleared")
                #st.rerun()
                st.session_state.confirm_delete = False
                st.session_state.delAllCheck = False
            else:
                st.session_state.confirm_delete = False
                st.warning("Check the box and hit delete. Warning, will delete all data!")

This is my sub call from utils.py that deletes all data:

def clear_all_history():
    """Clear all history"""
    df = pd.DataFrame(columns=['date', 'name, 'customergroup'])
    df.to_csv('data/customers.csv', index=False)
    #print("All history cleared")

Is there a better way to design this workflow or maybe use a different function to achieve what I want?

Usually when a button click doesn’t work the first time, it’s because the change you want to do is happening after the page re-runs. In other words, the order of operations for a streamlit widget change is: 1. run the callback and 2. re-run the page. If you don’t use a callback, the data won’t get cleared until you hit the if statement during the re-run, so if you wanted the data to change before that, it wouldn’t have the desired effect

In terms of the delAllCheck session_state, the use is a bit confusing. Since you have a checkbox with that key, you don’t need to assign it to another session_state. If you set the key, it automatically sets the session state when the widget is interacted with. So the most simple way of creating the checkbox is:

st.checkbox("Delete all history", value=False, key="delAllCheck")

Putting it all together, you can do this:

def button_clear():
    if st.session_state.get('delAllCheck', True):
        df = clear_all_history()
        st.success("All history has been cleared")
        st.session_state.delAllCheck = False
    else:
        st.warning("Check the box and hit delete. Warning, will delete all data!")
        with col1:
            st.checkbox("Delete all history", value=False, key="delAllCheck")
            butclick = st.button("Confirm", on_click=button_clear)

Oh the deletion works perfectly now. Thanks!

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