Missing value from two fields in a form

Summary

My streamlit form app seems to not capture the input from two fields. I want to insert the values from three text input fields into my database.

Steps to reproduce

First I scan a bar code into the barcode_create_input field and when I click the button, a query will verify if that barcode exists in the database and if not, it will ask you to fill a simple form to create a new product.
When you finish to fill in the new_manufacturer and new_product fields and click the “Create” button, another query will execute and insert the three fields (barcode, new_manufacturer and new_product) into the database.
Currently it only register the barcode in the db, I don’t know why I can’t get the other two values. I tried to st.write but it does not write on screen.

Code snippet:

import streamlit as st

from python_scripts.insert_page_queries import check_barcode_exists, insert_new_product


def main():
    st.set_page_config(page_title='My Inventory Control',
                       page_icon='.\logo2.jpg',
                       layout='centered', initial_sidebar_state='auto')

    with st.container():

        header_title = 'My Inventory Control'
        st.title(header_title)

        tab_create_products, tab_input_products, tab_output_products = st.tabs(['Create Products', 'Input Products',
                                                                                'Output Products'])

        with tab_create_products:
            barcode_create_input = st.text_input(label='Barcode')
            check_barcode_button = st.button('Check Barcode')

            if barcode_create_input and check_barcode_button:
                result_check_barcode = check_barcode_exists(barcode=barcode_create_input)

                if len(result_check_barcode) > 0 and result_check_barcode[0][0] == barcode_create_input:
                    st.write(f'Barcode {result_check_barcode[0][0]} already exists.')

                elif len(result_check_barcode) == 0:
                    st.write('Barcode does not exist. Please create a new product.')

                    # Form to create new product
                    with st.form(key='form_create_product'):
                        new_manufacturer = st.text_input(label='Manufacturer')
                        new_product = st.text_input(label='Product Name')
                        submit_button = st.form_submit_button(label='Create')

                        if len(new_manufacturer) > 0 and len(new_product) > 0:
                            st.write(new_manufacturer, new_product)
                            insert_new_product(barcode=barcode_create_input, manufacturer=new_manufacturer,
                                               product_name=new_product)

                            if submit_button:
                                st.write('New product created successfully')

                        elif len(new_manufacturer) == 0 or len(new_product) == 0:
                            st.write('Please fill in all fields.')

            elif check_barcode_button and not barcode_create_input:
                st.write('Please enter a barcode.')


if __name__ == '__main__':
    main()

You have an issue with nested buttons.

result_check_barcode is only going to be true on a page load resulting from that click. If you trigger a page reload from something nested inside that button output, it will all go away.

So everything inside if barcode_create_input and check_barcode_button: is only going to display for one page load. You do include a form and those widgets within the form prevent a page load until you click the form submit button. Hence, as soon as you fill out the form and click submit, the page is going to reload with result_check_barcode and your form is going to go away.

These widgets inside your form will therefore never have an opportunity to output anything but their default, empty-string values:

new_manufacturer = st.text_input(label='Manufacturer')
new_product = st.text_input(label='Product Name')

One solution is to get rid of the barcode check button altogether. I’ve put in some fake functions where you had imports:

import streamlit as st

if 'products' not in st.session_state:
    st.session_state.products=[]

def check_barcode_exists(barcode):
    return []

def insert_new_product(barcode, manufacturer, product_name):
    st.session_state.products.append((barcode,manufacturer,product_name))

def clear():
    st.session_state.barcode_input = ''

def main():
    st.set_page_config(page_title='My Inventory Control',
                       page_icon='.\logo2.jpg',
                       layout='centered', initial_sidebar_state='auto')

    with st.container():

        header_title = 'My Inventory Control'
        st.title(header_title)

        tab_create_products, tab_input_products, tab_output_products = st.tabs(['Create Products', 'Input Products',
                                                                                'Output Products'])

        with tab_create_products:
            barcode_create_input = st.text_input(label='Barcode', key='barcode_input')

            if barcode_create_input:
                result_check_barcode = check_barcode_exists(barcode=barcode_create_input)

                if len(result_check_barcode) > 0 and result_check_barcode[0][0] == barcode_create_input:
                    st.write(f'Barcode {result_check_barcode[0][0]} already exists.')

                elif len(result_check_barcode) == 0:
                    st.write('Barcode does not exist. Please create a new product.')

                    # Form to create new product
                    with st.form(key='form_create_product'):
                        new_manufacturer = st.text_input(label='Manufacturer')
                        new_product = st.text_input(label='Product Name')
                        submit_button = st.form_submit_button(label='Create')

                    if submit_button:
                        if len(new_manufacturer) > 0 and len(new_product) > 0:
                            st.write(new_manufacturer, new_product)
                            insert_new_product(barcode=barcode_create_input, manufacturer=new_manufacturer,
                                            product_name=new_product)
                            st.success('New product created successfully')
                            st.button('Continue', on_click=clear)

                        elif len(new_manufacturer) == 0 or len(new_product) == 0:
                            st.warning('Please fill in all fields.')
            else:
                st.write('Please enter a barcode.')


if __name__ == '__main__':
    main()