Dash Pattern Matching Callbacks: Match in Input but Not in Output

I want to use Dash pattern matching callbacks' MATCH as an Input, without needing to Output to the same MATCH. Imagine I generate a long, random list of items, from which a user may select any number of items. As they select each item, I want to append that item to a list in real time. It's a long list of 1,000+ items, so I don't want to see the whole ALL list, just the one they've selected in real time, so I can do a fast, efficient callback.

Something like the following:

from dash import Dash, dcc, html, Input, Output, State, MATCH, ALL
import dash_bootstrap_components as dbc

app = Dash(__name__, suppress_callback_exceptions=True)

# HTML table header and rows
header = html.Thead(html.Tr([html.Th("Add Part"), html.Th("Description")]))
rows = html.Tbody(
    [
        html.Tr(
            [
                html.Td(
                    dbc.Button(
                        "Add",
                        id={"type": "part_add", "index": i},
                        n_clicks=0,
                    ),
                ),
                html.Td(f"Index {i}"),
            ]
        )
        for i in range(1000)
    ]
)

app.layout = html.Div([
    dcc.Store(id="my_list", storage_type="local", data=[]),
    dbc.Table(
        [header, rows],
        bordered=True,
        striped=True,
    )
])


@app.callback(
    Output("my_list", "data"),
    Input({"type": "part_add", "index": MATCH}, "id"),
    State("my_list", "data"),
)
def match_callback_test(
    part_add_id,
    my_list_data 
):
    return my_list_data.append(part_add_id)

Is the above possible, with a different pattern? I get a JavaScript console error if I run the above.

2

1 Answer

If MATCH is used, MATCH also needs to be on all of the Outputs. Just use ALL instead and check which id was triggered with ctx. Working example:

from dash import (
Dash,
dcc,
html,
Input,
Output,
State,
MATCH,
ALL,
ctx,
exceptions,
no_update,
)
import dash_bootstrap_components as dbc

app = Dash(__name__, suppress_callback_exceptions=True)

# HTML table header and rows
header = html.Thead(html.Tr([html.Th("Add Part"), html.Th("Description")]))
rows = html.Tbody(
    [
        html.Tr(
            [
                html.Td(
                    dbc.Button("Add", id={"type": "part_add", "index": i}, n_clicks=0,),
                ),
                html.Td(f"Index {i}"),
            ]
        )
        for i in range(10)
    ]
)

app.layout = html.Div(
    [
        dcc.Store(id="my_list", storage_type="local", data=[]),
        dbc.Table([header, rows], bordered=True, striped=True,),
    ]
)


@app.callback(
    Output("my_list", "data"),
    Input({"type": "part_add", "index": ALL}, "n_clicks"),
    State("my_list", "data"),
)
def match_callback_test(part_add_id, my_list_data):

    trigger = ctx.triggered_id
    if trigger:
        my_list_data.append(trigger["index"])
        return my_list_data
    return no_update


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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Alexander Ross

Alexander Ross

Gaming, Esports & Interactive Media Writer

Alexander Ross has covered the video game industry for a decade, writing deep dives on game design, esports tournaments, VR developments, and gaming culture.

Share this article
Twitter Facebook Pinterest