Black Lives Matter. Please consider donating to Campaign Zero's mission of ending police violence in America.
https://www.joincampaignzero.org

Using Dash callbacks with dynamically created ids

Hi all,

I will first describe the goal of my app and then what I have done and the issue I’m having:

Goal:

  1. Create a dash table with an id defined by an option in a drop down menu.
  2. Be able to add arbitrary amount of rows to that table (perhaps with a button).
  3. Be able to create multiple instances of the above (up to the amount in the drop down menu or more or less).

So far I figured that the best way to add arbitrary amount of rows to a table is to initiate it with no rows and then have a button that appends a row to the table via:

@app.callback(
    Output('table1', 'data'),
    [Input('button1', 'n_clicks')],
    [State('table1', 'data'),
     State('table1, 'columns')])
def add_row(n_clicks, rows, columns):
    if n_clicks > 0:
        rows.append({c['id']: '' for c in columns})
    return rows

I also managed to generate a table with associated ‘add row’ button via:

@app.callback(
    Output('tables_div', 'children'),
    [Input('button_add_table', 'n_clicks')],
    [State('dropdown_options', 'value')])
def add_table(click, dropdownvalue):
    
    if click != None:
        
        table = add_new_table(str(energy)+material)
        
        B = html.Button(
            'Add Row',
            id = 'add_row' + str(dropdownvalue),
            className='one columns',
            style={'marginTop':'25px'}
        )
        
        D = html.Div(
            children=[
                table
            ],
            className='ten columns'
        )
        
        return [D,B]
    else:
        raise PreventUpdate

where the function to create a table is:

def add_new_table(table_id):
    table = dash_table.DataTable(
        id=table_id,
        data=[],
        columns=hvl_table_columns,
        style_cell = {
                'font_family': 'cursive',
                'font_size': '26px',
                'text_align': 'center'
        },
        style_header={
            'backgroundColor': '#696969',
            'color': 'white',
            'fontWeight': 'bold'
        }
    )
    
    return table

My problem is that because a table and a button are dynamically created, the callback for adding rows to a table via that button doesn’t work. Ideally I would like it to be something like:

@app.callback(
    Output(str(i), 'data'),
    [Input('add_row' + str(i), 'n_clicks')],
    [State(str(i), 'data'),
     State(str(i), 'columns')]) for i in table_ids  #This being the main difference from the callback to add rows above
def add_row(n_clicks, rows, columns):
    if n_clicks > 0:
        rows.append({c['id']: '' for c in columns})
    return rows

where table_ids is just a list of ids I generate when I create the tables and I can append to it if a new table is created in the ‘add_table’ callback.

This approach doesn’t work so I need help. I tried looking into dynamically creating callbacks as explained here but I couldn’t figure out how to implement it into my code. Maybe anyone has other ideas of how this can be done? Is it even possible to generate callbacks while the app is running? If not, then how can I make a generic callback to work for a list of ids?

Thanks