Generate list of State objects


#1

I’m building an app in which components are dynamically added to the layout, and programatically assigned unique id’s. I’d like to chart calculations based on all the present inputs. This is where I’m stuck. How do I go about generating a list of State objects for a callback to those values? (e.g. some instances will have two components added, while others could have eight). Apologies if this is too duplicate-y, but I’ve pored over the other “dynamic UI” topics and its still not clicking for me.

    import dash
    import flask
    import dash_core_components as dcc
    import dash_html_components as html

    external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']

    server = flask.Flask(__name__)

    app = dash.Dash(__name__, external_stylesheets=external_stylesheets, server=server)

    app.config['suppress_callback_exceptions']=True


    app.layout= html.Div([
        html.H1("Test"),
        html.Div([
            html.Div([
                html.Div(id='output-container', className='row'),
                dcc.Input(id='input-box', type='text'), 
                html.Button('Add layer', id='button')
                ], className="four columns")], className="Row"
        )
    ])


    @app.callback(
        dash.dependencies.Output('output-container', 'children'),
        [dash.dependencies.Input('button', 'n_clicks')])
    def render_layout(n_clicks):

        if not n_clicks:
            n_clicks= 0 
        rows = []

        for i in range(n_clicks):
            row = html.Div([
                    html.Div([
                        dcc.Dropdown(
                            id='film-{}'.format(i), 
                            placeholder='Film',
                            options=[{'label':i, 'value':i} for i in [1, 2, 3, 4]])
                        ], 
                        style= {
                            'width':'30%', 
                            'display':'table-cell'
                        }
                    ),
                    html.Div([
                        dcc.Input(id='thickness-{}'.format(i),placeholder="Layer {}".format(i), type='text')
                        ],
                        style={
                            'width':'67%',
                            'display':'table-cell'
                        }
                    )
                ], className="row")
            rows.append(row)

            return html.Div([
                        html.Div(list(reversed(rows))), # reversed to put base layer at 0
                        ])


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

#2

The way I went about doing this is I created a hidden div that stored the values in a list that I would read with a callback.

edit: looking back at my code I was not able to figure out how to call values from component ids. It was very hacky. I do not know that the scope of a callback is capable of generating state objects from information of the dom.


#3

I guess a broader question is what would be a better approach to aggregating the values added into dynamically generated components (or am I pushing the boundaries of the Dash use case)


#4

I think you are pushing the boundaries of Dash.
The problem you are running into is scope and how can you keep track of the components the user has generated.

Without making use of global variables I don’t see how you can do this (except passing values with a hidden div).

Here is a thread where some explorers ran into this same problem.