Callback troubles with nested components (multiselect dropdown in html/dbc Table)

I am building a table using dash bootstrap components as I would like to have a multi-select dropdown in the datatable. This works in, but when I try to trigger a callback based on my selection, the callback doesn’t fire. The table is created using the following code:
*note df = a dataframe of variable length with columns q_uuid and questions used to build the table which is loaded as an output child from a different callback following a button press.

@app.callback(Output("question_table_location","children"),
              Input("load_button", "n_clicks"))
def load_output(load_b,instance_id):
############################
        # Build HTML table
        table_header = [
            html.Thead(html.Tr([html.Th("Selected"),
                                html.Th("Question_UUID"),
                                html.Th("Question"),
                                html.Th("Category")]))]

        table_row = []
        for row in range(df.shape[0]):
            temp_row = html.Tr([html.Td(dcc.Checklist(options=[{'label': '', 'value': 'Checked'}],
                                                      value=[''],
                                                      id=f'cb_{row}')),
                                html.Td(df.loc[row,'q_uuid']),
                                html.Td(df.loc[row,'question']),
                                html.Td([dcc.Dropdown(
                                    [{"label": f"{vci}",
                                      "value": vci} for vci in categories],
                                    placeholder="Category",
                                    id=f"cat_dd_{row}",
                                    multi=True,
                                    style={'width':'100%'})])])
            table_row.append(temp_row)
        table_body = [html.Tbody(table_row)]
        table = dbc.Table(table_header + table_body, bordered=True,id='question-table',style={"width": "1400px"})
     return table

because I have a variable number of dropdowns, I tried to set the output up as follows:

@app.callback(Output("select_all_button", "disabled"),
              [Input(f"cat_dd_{row}","value") for row in range(df.shape[0])])
def select_row(*args):
        button_id = ctx.triggered_id

        print(button_id)
        print(args)
        return False

If I remove the callback the table builds fine, but with the callback things hang when I press the button to build the table.
Any suggestions would be appreciated!.

Hello @jmcmplot,

Welcome to the community!

Instead of trying to create inputs for the number of inputs, you can utilize pattern-matching, which will keep things closer and even dynamic between data changing. :slight_smile:

table:

############################
        # Build HTML table
        table_header = [
            html.Thead(html.Tr([html.Th("Selected"),
                                html.Th("Question_UUID"),
                                html.Th("Question"),
                                html.Th("Category")]))]

        table_row = []
        for row in range(df.shape[0]):
            temp_row = html.Tr([html.Td(dcc.Checklist(options=[{'label': '', 'value': 'Checked'}],
                                                      value=[''],
                                                      id=f'cb_{row}')),
                                html.Td(df.loc[row,'q_uuid']),
                                html.Td(df.loc[row,'question']),
                                html.Td([dcc.Dropdown(
                                    [{"label": f"{vci}",
                                      "value": vci} for vci in categories],
                                    placeholder="Category",
                                    id={"index":f"{row}","type":"cat_dd"},
                                    multi=True,
                                    style={'width':'100%'})])])
            table_row.append(temp_row)
        table_body = [html.Tbody(table_row)]
        table = dbc.Table(table_header + table_body, bordered=True,id='question-table',style={"width": "1400px"})

callback:

@app.callback(Output("select_all_button", "disabled"),
              Input({'index':ALL,'type':'cat_dd'},"value")
def select_row(_):
        button_id = ctx.triggered_id

        print(button_id)
        print(args)
        return False

Hopefully this will work for you. :slight_smile:

Thanks for the quick response! I implemented what you suggested (which makes total sense), but the same thing happens, that is when I click the button to load the table, nothing happens, but when I hide the select_row callback, the button press loads the table with all the dropdowns etc. It seems tough to debug as I don’t see any output following the button press - it’s as if it never makes it to it’s associated callback…

Are you running your app with debug=True?

yup, but as far as outputs things seem to just hang, there are no errors etc

@app.callback(Output("select_all_button", "disabled"),
              Input({'index':ALL,'type':'cat_dd'},"value")
def select_row(_):
        if ctx.triggered.value:
            button_id = ctx.triggered_id

            print(button_id)
            print(args)
            return False
      return dash.no_update

Try changing to this.

Thanks - it’s working now - the problem was I was already outputting to select_all_button somewhere else.
Thanks for your help!

1 Like