✊🏿 Black Lives Matter. Please consider donating to Black Girls Code today.
⚡️ Concerned about the grid? Kyle Baranko teaches how to predicting peak loads using XGBoost. Register for the August webinar!

Dynamic Input on forms

I want to make a form where the user can add new inputs if he needs. For example, a user is completing a form about his favorite food, and I have an Input for food, where he types Apple. Now, I have a button which lets the user add another line of input, this is a different Input! The user will type another food, and I can add a different ID to this Input. But I still can’t access both inputs.

Heres an example.

import dash
import dash_bootstrap_components as dbc
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State

app = dash.Dash(
    external_stylesheets=[dbc.themes.LUX],
    # these meta_tags ensure content is scaled correctly on different devices
    # see: https://www.w3schools.com/css/css_rwd_viewport.asp for more
    meta_tags=[
        {"name": "viewport", "content": "width=device-width, initial-scale=1"}
    ],
)

content = html.Div(id="page-content")
app.layout = html.Div([dcc.Location(id="url"), content])

dynamic_input = html.Div([
    html.Div([
        dcc.Input(id="input-0"),
    ], id="dynamic-input"),
    dbc.Button("Button", id="button"),
    dcc.Store(id="number-input", storage_type="local"),
    html.Div(id="callback-print")
])

@app.callback(Output("page-content", "children"), [Input("url", "pathname")])
def render_page_content(pathname):
    if pathname in ["/", "/page-1"]:
        return dynamic_input
    # If the user tries to reach a different page, return a 404 message
    return dbc.Jumbotron(
        [
            html.H1("404: Not found", className="text-danger"),
            html.Hr(),
            html.P(f"The pathname {pathname} was not recognised..."),
        ]
    )

@app.callback(
    [Output("dynamic-input", "children"), 
     Output("number-input", "children")], 
    [Input("button", "n_clicks")],
    [State("number-input", "children")])
def add_input(clicks, number):
    global number_inputs
    if clicks:
        new_input = []
        for x in range(int(number)):
            new_input.append(dcc.Input(id=f"input-{x}"))
        number_inputs = int(number) + 1
        return new_input, number_inputs
    number_inputs = 1
    return dcc.Input(), 1

number_inputs = 1

@app.callback(
    Output("callback-print", "children"),
    [Input(f"input-{x}", "value") for x in range(number_inputs)]
)
def print_all(*inputs):
    print(number_inputs)
    print(inputs)
    for i in inputs:
        print(i)
    return None


if __name__ == "__main__":
    app.run_server(debug=True)

Check out pattern matching callbacks :slightly_smiling_face: