First Edit Not Registered in st.data_editor - Requires Second Attempt to Save Changes

Description:
When using st.data_editor in my Streamlit application, I encounter a bug where the first edit made to a table is not registered and the value reverts to the original after input. However, if I make the same edit a second time, the change is successfully applied.

Steps to Reproduce:

  1. Launch the Streamlit application with a DataFrame displayed using st.data_editor.
  2. Edit any value in the table for the first time.
  3. Observe that the value reverts to the original after the edit.
  4. Edit the same value again.
  5. Notice that the second edit is successfully applied.

Expected Behavior:
The first edit should be registered immediately without requiring a second attempt.

Observed Behavior:
The first edit is discarded, and only the second edit is successfully applied.

Relevant Code Snippet:

edited_df = st.data_editor(
    station_data_df,
    hide_index=True,
    column_config=column_config,
    use_container_width=True,
    key=f"st.editor{i}",
    num_rows="dynamic",
)
```.

**Request:**  
Is this a known issue or expected behavior? How can I ensure the first edit is correctly registered? Any insights or workarounds would be greatly appreciated!  

Thank you!

That code works as expected for me. I suspect there may be more code that is relevant.

Summary:
The issue seems to originate from how station_data_list is initialized when using attributes from a Pydantic data model (charger object). If constant values are used in the dictionary definition, the problem disappears. However, when dynamic values from the Pydantic model are used, the problem persists, causing the table to revert changes on reruns.


Steps to Reproduce:

  1. Use the following dictionary initialization in the create_charging_process() function:

      def create_charging_process(self, i, station_data):
        """Create UI for chargers data input."""
        station_data_list = [
            {
                "Charger Name:": charger.charger_name,
                "Max power (kW):": charger.max_power,
                "Required charge (kWh):": charger.required_charge,
                "Revenue (€/kWh):": charger.charging_revenue,
                "Day of week:": charger.week_day_type,
                "Vehicle number": charger.vehicle_number,
                "Arrival time": charger.arrival_time,
                "Stay length": charger.length_stay,
                "Duplication": False,
                "Delete": False,
            }
            for charger in station_data
        ]
    
        station_data_df = pd.DataFrame(station_data_list)
    
  2. Display the DataFrame using st.data_editor:

    edited_df = st.data_editor(
        station_data_df,
        hide_index=True,
        column_config=column_config,
        use_container_width=True,
        key=f"st.editor{i}",
        num_rows="dynamic",
    )
    

Observed Behavior:

  • When attributes from the Pydantic model (charger object) are used, the first edit is reverted. A second attempt is required to apply the change.
  • If constant values are used, the table works as expected with no reversion.

Thank you for your assistance! :rocket:

Typically, the double submit problem occurs with the anti-pattern of updating Session State from the output of a widget.

Are you dealing with a similar situation to this: Shuffling Dataframe in data_editor with checkboxes - #2 by mathcatsand

That code seems to work for me too, as long as the items in station_data don’t change. But if they change, a new data_editor widget is created and the edits made by the user in the old widget are lost.

I am assuming that the second part of the code is also part of the body of the function, otherwise I am unable to make it work.

I have the same problem, any interruption of the data_editor causes the first edit to get missed. In my case I wanted to save the changes to a csv file, and my best solution is to use a button outside the edit code. Are there any better methods?

import streamlit as st
import pandas as pd

PASSWORD = "abc123"
blog=pd.read_csv('./blog/data/blog.csv')

st.set_page_config(layout="wide")

def main():
    st.title("Test")

    password = st.sidebar.text_input("Enter password", type="password")

    if password == PASSWORD:
        st.sidebar.success("Access granted!")

        edited_blog=st.data_editor(
            blog,
            use_container_width=False,
            column_config={"Thesis": st.column_config.TextColumn(width=1000)}
            )

    else:
        st.sidebar.error("Access denied. Incorrect password.")

    save=st.sidebar.button("Save dataset")    
    if save:
        edited_blog.to_csv("./blog/data/blog.csv", index=False)   

if __name__ == "__main__":
    main()

Your observation is correct, this is a very peculiar problem. I press return button on the keyboard after each edit on the field to save the value. Then save the table.

A different method would be not reading blog from the csv file on each rerun. It is your call whether that is better for your particular needs or not.