Multiple Button - Dynamic Callbacks!

Hello Everyone :grin:

Hope you doing great !

I’m a beginner and I get some diffiulties to achieve what I want… Basically I would like n button that could share the same callback when they are clicked. The callback will then put the id of the specific button in a list and that’s it !

For the example i have took 2 button but in reality it has to be dynamic since the number of button is not fixed so the id and callback too :smiley:

I have created a random div that could also be used has an output ! I have tried many solution of Matching Pattern but without success… So if anyone of you could help me it would be amazing :innocent:

app = dash.Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])

#List to stock when a button has been clicked we put the id of the button there
List_Interaction = []

#Simple div for output callback
Screen = html.Div(id='dd-output-container')

# Two Button that should have a dynamic id
Button1 = html.Button('Button 1',id='btn1',style={
    'backgroundColor':'white'
})

Button2 = html.Button('Button 2',id='btn2',style={
    'backgroundColor':'white'
})

#simple container to stock the Button
Container_div = html.Div(
    [
       Screen,
       Button1,
       Button2
    ],
    style={
    'position': 'absolute',
    'left': '0px',
    'top': '0px',
    'margin-left': '0%',
    'outline': '0',
    'height': '100%',
    'width': '100%',
    },
    id = 'container-div'
)




app.layout = html.Div([

    Container_div
])

if __name__=='__main__':
    app.run_server(host="localhost", port=5005,debug=False,dev_tools_ui=False)

So has you can see there, nothing big, only 2 buttons that are located in a div and i would like to make sort of we have a callback that will be called whenever one of those button is clicked. But it has to be dynamic since the number of button is not fixed !

Thanks a lot :smile:

Hello @HelloWorld1801 !

It seems indeed like a job for a Pattern Matching callback. But I think you would also benefit from using dash callback context: Determining Which Callback Input Changed | Dash for Python Documentation | Plotly

If I understood your goal correctly, this sample app should do what you want (it uses Dash >= 2.4!):

import dash
from dash import Input, Output, State, ALL, callback, ctx
from dash import html,dcc
import plotly.express as px
import pandas as pd
import dash_bootstrap_components as dbc

app = dash.Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])

#List to stock when a button has been clicked we put the id of the button there
List_Interaction = []

#Simple div for output callback
Screen = html.Div(id='dd-output-container',children=[])

# A button to create new buttons
Button_create = html.Button(
    'Create Button',id='create', n_clicks=0, 
    style={'backgroundColor':'white'}
    )

# A div to hold created buttons
Button_container = html.Div(id='button-container',children=[])

#simple container to stock the Button
Container_div = html.Div(
    [
       Button_create,
       Button_container,
       Screen
    ],
    style={
        'position': 'absolute',
        'left': '0px',
        'top': '0px',
        'margin-left': '0%',
        'outline': '0',
        'height': '100%',
        'width': '100%',
    },
    id = 'container-div'
)

# Callback to create new buttons
@callback(
    Output('button-container','children'),
    Input('create','n_clicks'),
    State('button-container','children'),
    prevent_initial_call=True
)
def create_new_button(n_clicks, current_buttons) :

    if n_clicks == 0 :
        raise dash.exceptions.PreventUpdate

    new_button = html.Button(
        f'Button {n_clicks}',
        id={'type':'btn_created', 'index':n_clicks},
        style={'backgroundColor':'white'},
        n_clicks=0
        )
    
    return current_buttons + [new_button]

# Callback to update list with last clicked button
@callback(
    Output('dd-output-container','children'),
    Input({'type':'btn_created','index':ALL}, 'n_clicks'),
    State('dd-output-container','children'),
    prevent_initial_call=True
)
def update_list(current_clicks, previous_clicks) :

    trigger = ctx.triggered_id['index']

    # numbre of clicks of last trigger
    trigger_clicks = ctx.triggered[-1]['value']

    #  we include this to prevent the list from updating when we create a new button (when its number of clicks is 0)
    if trigger_clicks == 0 :
        raise dash.exceptions.PreventUpdate
        
    last_click  = f'Button {trigger}'
    
    return previous_clicks + [last_click] + [html.Br()]

app.layout = html.Div([
    Container_div
])

if __name__=='__main__':
    app.run_server(host="localhost", port=5005,debug=False,dev_tools_ui=False)
    #app.run_server(debug=True)
3 Likes

Thanks a lot ! it will definitly do the trick ! You helped me a lot :smiley:

Wish you a great day !

2 Likes