1

I want to open this post as I can't find anything on the official documentation from streamlit or any resources that mentioned how to do this. After some trial and error I have figured out a way, and will post the answer below. This is a function that in R shiny is called dynamic UI, here's the question.

How to generate dynamic input widgets depending on the value from a different input widget? For example see below picture, the numbers of text_input called Product Code i depends on the value from the number_input called Number of Products. So if there are x number of products, there will be x number of text_input generated dynamically. Moreover, the value inside the generated text_input can be extracted as well.

enter image description here

Subaru Spirit
  • 394
  • 3
  • 19

2 Answers2

1

Here is one way to do this.
First, use list comprehension to store keys (variables to use to extract values from text_input later) and values (text_input).
Next, use key and value to set the attribute in a class.
The value from text_input labelled as product2 can be extracted using the attribute within the class using p.product2 for example.

import streamlit as st

number_of_products = st.sidebar.number_input(label="Number of Products",
                                     min_value=0, max_value=20, value=1)

class Products:
    pass

p = Products()
keys = [str("product"+str(x+1)) for x in range(number_of_products)]
values = [st.sidebar.text_input(label=f"Product Code {x+1}", value=0) for x in range(number_of_products)]

for key, value in zip(keys, values):
    setattr(p, key, value)

# each key's value is stored in the class as an attribute
st.write(p.product2)

Using dictionary and exec command can also dynamically declare variables, but when the value inside the text_input is not a number, it will generate an error.

Subaru Spirit
  • 394
  • 3
  • 19
1

Generating dynamic input widget content is possible when using streamlit's session state. However, there is a potential drawback of streamlit refreshing the page upon input widget interaction.

One way to solve for this is to create multiple forms. For example, in your case you can create one form for "Number of Products", and update this value to the session state.

Next, you can create another form that takes in this "Number of Products" parameter and creates x number of input widgets.

import streamlit as st

with st.form("Number of Products"):
  numProducts = st.number_input('Insert a number', key='numProducts')
  submitForm = st.form_submit_button("Set Product Number")

  if submitForm:
    st.success("Please assign product codes below")

if 'numProducts' in st.session_state.keys():
  with st.form("Product Codes"):
    for i in range(st.session_state['numProducts']):
      # insert text inputs with keys here

Hope this helps!

Doracahl
  • 336
  • 2
  • 14