Reputation: 46
I want to create a form to dynamically add and remove "text_input" fields. I am able to add a "text_input" each time I click on the "➕ Add field" button.
However, I am unable to correctly remove a "text_field".
What I have achieved so far: Every time I click on the "❌" button, the last added "text_field" is removed.
However, I am unable to identify the occurrence of the button that is clicked on.
Below is the source code of the form. Thank you for your assistance.
import streamlit as st
FIELDS = []
DELETES = []
if "fields_size" not in st.session_state:
st.session_state.fields_size = 0
st.session_state.fields = []
st.session_state.deletes = []
def add_field():
st.session_state.fields_size += 1
def delete_field():
pass
st.header("Dynamic form ⚒️")
st.divider()
# fields and types of the table
for i in range(st.session_state.fields_size + 1):
c1, c2 = st.columns(2)
with c1:
FIELDS.append(
st.text_input(f"Field {i}", key=f"text{i}", label_visibility="visible"))
with c2:
DELETES.append(st.button("❌", key=f"delete{i}", on_click=delete_field))
st.session_state.fields = FIELDS
st.session_state.deletes = DELETES
st.button("➕ Add field", on_click=add_field)
Upvotes: 2
Views: 2052
Reputation: 21
Issue: The problem was that when filling in the text_input fields, the values were not being correctly saved to st.session_state.fields.
Solution: The issue arises from not updating st.session_state.fields when text inputs are filled. To fix this, we need to ensure that each text_input updates the corresponding value in st.session_state.fields and the values persist when deleting fields.
import streamlit as st
def add_field():
st.session_state.fields_size += 1
st.session_state.fields.append('') # Add a new empty field
def delete_field(index):
if st.session_state.fields_size > 0:
del st.session_state.fields[index]
st.session_state.fields_size -= 1 # Decrease the field count
if "fields_size" not in st.session_state:
st.session_state.fields_size = 0
st.session_state.fields = []
st.session_state.deletes = []
st.write(st.session_state.fields)
st.divider()
for i in range(st.session_state.fields_size):
c1, c2 = st.columns(2)
with c1:
field_value = st.text_input(f"Field {i + 1}", key=f"text{i}", value=st.session_state.fields[i], label_visibility="visible")
st.session_state.fields[i] = field_value # Update session_state.fields
with c2:
st.markdown("<br>", unsafe_allow_html=True)
if st.button(f"❌", key=f"delete{i}", on_click=delete_field, args=(i,)):
pass
st.button("➕ Add Field", on_click=add_field)
This code should work for you :)
Upvotes: 2
Reputation: 1
import streamlit as st
import pandas as pd
import uuid
def add_field():
st.session_state.fields[str(uuid.uuid4())] = ""
def delete_field(i):
st.session_state.fields.pop(i)
if "fields" not in st.session_state:
st.session_state.fields = {}
for index, i in enumerate(list(st.session_state.fields.keys())):
c1, c2 = st.columns(2, vertical_alignment="bottom")
with c1:
st.text_input(f"Field {index}", value=st.session_state.fields[i], key=i)
st.session_state.fields[i] = st.session_state[i]
with c2:
st.button("❌", key=f"delete{i}", on_click=delete_field, args=(i,))
st.write(st.session_state.fields)
st.button("➕ Add field", on_click=add_field)
My version for streamlit==1.36.0
Upvotes: 0
Reputation: 11
This solution can be improved if you set columns vertical alignment to "bottom", like c1, c2 = st.columns(2, vertical_alignment="bottom")
.
If you do that, the website will look like this:
Code:
import streamlit as st
def add_field():
st.session_state.fields_size += 1
def delete_field(index):
st.session_state.fields_size -= 1
del st.session_state.fields[index]
del st.session_state.deletes[index]
st.header("Dynamic form ⚒️")
st.divider()
if "fields_size" not in st.session_state:
st.session_state.fields_size = 0
st.session_state.fields = []
st.session_state.deletes = []
# fields and types of the table
for i in range(st.session_state.fields_size):
c1, c2 = st.columns(2, vertical_alignment="bottom")
with c1:
st.session_state.fields.append(st.text_input(f"Field {i}", key=f"text{i}"))
with c2:
st.session_state.deletes.append(st.button("❌", key=f"delete{i}", on_click=delete_field, args=(i,)))
st.button("➕ Add field", on_click=add_field)
Upvotes: 0
Reputation: 34
It seems that you want to remove a specific field when you click the delete button next to it, but you currently only remove the last field added.
Here's how you can fix this:
import streamlit as st
def add_field():
st.session_state.fields_size += 1
def delete_field(index):
st.session_state.fields_size -= 1
del st.session_state.fields[index]
del st.session_state.deletes[index]
st.header("Dynamic form ⚒️")
st.divider()
if "fields_size" not in st.session_state:
st.session_state.fields_size = 0
st.session_state.fields = []
st.session_state.deletes = []
# fields and types of the table
for i in range(st.session_state.fields_size):
c1, c2 = st.columns(2)
with c1:
st.session_state.fields.append(st.text_input(f"Field {i}", key=f"text{i}"))
with c2:
st.session_state.deletes.append(st.button("❌", key=f"delete{i}", on_click=delete_field, args=(i,)))
st.button("➕ Add field", on_click=add_field)
This code should work for you too. Let me know.
Upvotes: -1