Output MATCH ids with specific string

Hello all!
I’m having a little bit of trouble with an output.
I created a layout with multiple buttons and a dropdown. These buttons have in their ids 1A, 2A, 3A, 1B, 2B, 3B, 1C, 2C, 3C, … and the dropdown A, B, C, …

I want to create a callback that changes the color of the buttons based on the dropdown value. If A: change all buttons in which the A is in their ID, …

I created this callback but its not working:

def _set_feedback(self, app):
        @app.callback(
            Output({'type': "button", 'index': MATCH}, "color"),
            Input("dropdown", "value"),
            prevent_initial_call = True
        )
        def change_color(value):
            if value == "A":  
                return "danger"

Any suggestions?

Hi @dash_ploty_noob, welcome to the forums.

What is your index in this case? Do you need your indexfor other matching callbacks?

Thank you @AIMPED !!

The ids are the following id={‘type’: “button”, ‘index’: letter+str(number)}. The buttons are generated in a for cycle from a list of letters and numbers

Now I understand what you are after. Actually pattern matching callbacks don’t work like that.

The MATCH does not refer to value but rather to a matching component. Take this example:

from dash import Dash, html, Input, Output, MATCH, ctx

app = Dash(__name__)
app.layout = html.Div(
    [
        html.Div(
            [
                html.Button(f'button_{idx}', id={'type': 'btn', 'index': idx})
                for idx in range(3)
            ]
        ),
        html.Div(
            [
                html.Div(id={'type': 'out', 'index': idx})
                for idx in range(3)
            ]
        )
    ]
)


@app.callback(
    Output({'type': 'out', 'index': MATCH}, 'children'),
    Input({'type': 'btn', 'index': MATCH}, 'n_clicks'),
    prevent_initial_call=True
)
def output(n_clicks):
    triggered_index = ctx.triggered_id.index
    return f'button wth index {triggered_index} has been clicked {n_clicks} times.'


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

mred pmcb

It’s not pretty but it does the job:

from dash import Dash, html, dcc, Input, Output, ALL, State

BTN_NUM = 10
CHARS = 'ABCDEFG'
COLORS = ['red', 'green', 'blue', 'yellow', 'white', 'purple', 'orange']
# len(COLORS) has to be the same as len(CHARS)

app = Dash(__name__)
app.layout = html.Div(
    [
        html.Div(
            [
                html.Div(
                    [
                        html.Button(
                            id={'type': f'btn_{char}', 'index': idx},
                            children=f'button_{char}_{idx}',
                            style={'background-color': 'gray'}
                        )
                        for idx in range(BTN_NUM)
                    ]
                )
                for char in CHARS
            ]
        ),
        html.Div(
            [
                dcc.Dropdown(
                    id='drop',
                    options=list(CHARS)
                ),
                html.Button(
                    id='reset',
                    children='RESET'
                )
            ]
        )
    ]
)


@app.callback(
    [
        Output({'type': f'btn_{char}', 'index': ALL}, 'style')
        for char in CHARS
    ],
    Input('drop', 'value'),
    [
        State({'type': f'btn_{char}', 'index': ALL}, 'style')
        for char in CHARS
    ],
    prevent_initial_call=True
)
def output(value, *states):

    # find index of selected char in CHARS
    outer_idx = CHARS.index(value)

    # assign color to selected char
    color = COLORS[outer_idx]

    # loop over values and change according to selection
    for i in range(BTN_NUM):
        states[outer_idx][i] = {'background-color': color}
    return states


@app.callback(
    [
        Output({'type': f'btn_{char}', 'index': ALL}, 'style', allow_duplicate=True)
        for char in CHARS
    ],
    Input('reset', 'n_clicks'),
    prevent_initial_call=True
)
def output(_):
    return [
        [{'background-color': 'gray'}] * BTN_NUM
    ] * len(CHARS)


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