So after couple of attempts, I have found a solution that works for me atleast.
- It allows user to select option from one col (i.e. “Add_Vendor”), which are populated in another col (i.e. “Vendor”). This way user can mimic multi_select in st.data_editor and all of the selected options are available in “Vendor” col.
- If the selected option from “Add_Vendor” col is not available in “Vendor” col, it is added, if it’s already available, then its deleted. This allows to user to add/remove entries from list col, which is also natively not editable.
- The addition/deletion is updated in the DB and the table is refreshed.
I’m sharing my code below for the community. This might not be an exact solution for the named topic i.e. [Multi_select for st.data_editor] but sometimes, stumbling upon different options can help brainstorm ideas.
function to push changes made in the table to the DB
def update_edit_row():
edited_rows = st.session_state.sla_editor.get(“edited_rows”, {})
added_rows = st.session_state.sla_editor.get(“added_rows”, )
deleted_rows = st.session_state.sla_editor.get(“deleted_rows”, )
# Establish a connection to the database
conn = get_connection()
cursor = conn.cursor()
# Process edited rows, email is being used as index here
if edited_rows:
row_index, row_data = next(iter(edited_rows.items()))
if “Add_Vendor” in row_data:
add_vendor_value = row_data[“Add_Vendor”]
# Fetch current Vendor column value from the database
cursor.execute(
“SELECT Vendor FROM SLA WHERE ROWID = ?”, (row_index + 1,)
)
result = cursor.fetchone()
current_vendor = result[0] if result else “”
# Split the current vendor values into a list and check for duplicates
vendor_list = current_vendor.split(“,”) if current_vendor else
if add_vendor_value in vendor_list:
# Remove Add_Vendor value if it already exists
vendor_list.remove(add_vendor_value)
else:
# Append Add_Vendor value to the existing Vendor column value
vendor_list.append(add_vendor_value)
# Update the Vendor column with the modified list
updated_vendor = “,”.join(vendor_list).strip(“,”)
# Update the Vendor column in the database
cursor.execute(
“”"
UPDATE SLA
SET Vendor = ?
WHERE ROWID = ?
“”“,
(updated_vendor, row_index + 1),
)
else:
column, value = next(iter(row_data.items()))
cursor.execute(
f”“”
UPDATE SLA
SET {column} = ?
WHERE ROWID = ?
“”“,
(value, row_index + 1), # SQLite ROWID starts at 1
)
# Process added rows
if added_rows:
for row_data in added_rows:
# Handle Add_Vendor column
add_vendor_value = row_data.pop(“Add_Vendor”, None)
current_vendor = row_data.get(“Vendor”, “”)
# Split the current vendor values into a list
vendor_list = current_vendor.split(”,“) if current_vendor else
if add_vendor_value:
if add_vendor_value in vendor_list:
# Remove Add_Vendor value if it already exists
vendor_list.remove(add_vendor_value)
else:
# Append Add_Vendor value to the Vendor column
vendor_list.append(add_vendor_value)
# Update the Vendor column in the row data
row_data[“Vendor”] = “,”.join(vendor_list).strip(”,“)
# Insert the row into the database
columns = “, “.join(row_data.keys())
placeholders = “, “.join([”?” for _ in row_data])
values = tuple(row_data.values())
cursor.execute(
f”””
INSERT INTO SLA ({columns})
VALUES ({placeholders})
“”“,
values,
)
# Process deleted rows to delete users from the database
if deleted_rows:
for row_index in deleted_rows:
try:
cursor.execute(“DELETE FROM SLA WHERE ROWID = ?”, (row_index + 1,)) # SQLite ROWID starts at 1
except Exception as e:
st.error(f"Error deleting row #{row_index}: {str(e)}”)
# Commit changes to DB, Clear Cached SLA Table, Close Connection, and rerun to update table in the UI
conn.commit()
fetch_sla.clear()
conn.close()
Display the SLA table in editable form
edit_data=st.data_editor(data, key=“sla_editor”, column_config=column_config, column_order=final_col, use_container_width=True, hide_index=True, num_rows=“dynamic”)
if any(st.session_state.sla_editor.values()):
update_edit_row()
st.rerun()
Screenshots
In the below screenshot, please observe that selecting “22 Media Corporation” in “Add/Delete Vendor” Col adds it in the “Vendor” Col, selecting it again, deletes it. Though the screenshot is for only one option, the user can select multiple options as well.