Callbacks to dynamically generated button

Hi All,
I am new to Dash and i am trying to make a kind of interactive dashboard for inventory management. There are several items which will be loaded from database


I want to have several small “Minus” buttons on each items like above to reduce the number when some one borrow, which i can do by a loop of this function

def makeitemcol(itemtype,item,quantity):

fonts = "2vw"

if (len(item) > 7 ) :

    fonts = "1.7vw"

imagestr = itemtype + "/" + item +".png"

col = dbc.Col([

                 dbc.Card([

                        html.Div([html.P(str(quantity))],style = CIRLE),

                        dbc.CardBody([

                        html.Div([html.P(item.capitalize())],style={"line-height": "1rem",'width': '90%', 'height': '100%','display': 'inline-flex','font-size': fonts,}),

                        # dbc.Button(html.I(className = "bi bi-plus-lg"),color="secondary", className="me-1",style=BUTP),  #{'width': '20%', 'display': 'inline-block'}),

                        dbc.Button(html.I(className = "fas fa-minus"),color="secondary", id="minusitem"+item, className="me-1",style=BUTM),   #{'width': '20%', 'display': 'inline-block'}),

                        dbc.CardImg(src=app.get_asset_url(imagestr), className = 'img',style={"display":"block","margin-left": "auto","margin-right": "auto",'width':'80%'}),

                                ]),

                            ],style={"border": "2px solid Gold","border-radius":"25px", "position": "relative"})

                ], width=2,)

return col

My problem now is how to match these button to callbacks. These buttons are dynamically generated so there is no fixed number of buttons and therefore callbacks will also need to generated dynamically.
Thanks in advance for any help.

Hi,

You can use pattern-matching callbacks in this case. Please take a look on the docs about this topic.

1 Like

Hi, thanks for the advice, i can get a simplify version of what i need using MATCH

@app.callback(

Output({'type': 'test1', 'index': MATCH}, 'children'),

Input({'type': 'minus', 'index': MATCH}, "n_clicks"),

State({'type': 'minus', 'index': MATCH}, 'id'),

)

def display_output(value, id):

quan = db.search(item.type == id["index"])[0].get("count")

if value :

    # print(id['index'])

    rem = quan-1

    if rem == 0 :

        db.remove(where('type')==id["index"])

    else :    

        db.update({'count': rem}, where('type')==id["index"])

    return html.Div(rem)

else :

    return html.Div(quan)

Now i only figure out how to trigger a refresh of page to update my page when some items reach 0 ^^

hi @Hiro.Nguyen,
I came up with a minimal reproducible example that might be helpful to you or others that wish to create dynamic bootstrap cards. Click to view executable Dynamic Cards notebook file.

A copy of the code below:

from jupyter_dash import JupyterDash
from dash import dcc, html, Input, Output, ALL, State, MATCH, ALLSMALLER
import plotly.express as px
import pandas as pd
import dash_bootstrap_components as dbc

df = pd.read_csv("https://raw.githubusercontent.com/Coding-with-Adam/Dash-by-Plotly/master/Callbacks/Pattern%20Matching%20Callbacks/Caste.csv")
df.rename(columns={'under_trial': 'under trial', 'state_name': 'state'}, inplace=True)

app = JupyterDash(__name__, external_stylesheets=[dbc.themes.CYBORG])

app.layout = html.Div(
    [
        html.Div(
            children=[
                html.Button("Add Card", id="add-chart", n_clicks=0),
            ]
        ),
        html.Div(id="container", children=[]),
    ]
)


@app.callback(
    Output("container", "children"),
    [Input("add-chart", "n_clicks")],
    [State("container", "children")],
)
def display_graphs(n, div_children):
    new_card = html.Div(
        style={
            "width": "45%",
            "display": "inline-block",
            "outline": "thin lightgrey solid",
            "padding": 10,
        },
        children=[
            dbc.Card(
                dbc.CardBody(
                    [
                        html.H5(
                            id={"type": "dynamic-title", "index": n},
                            children="",
                            className="card-title",
                        ),
                        html.P("The button will update the integer on top"),
                        dbc.Button(
                            "Update number",
                            color="primary",
                            n_clicks=0,
                            id={"type": "dynamic-button", "index": n},
                        ),
                    ],
                    id={"type": "dynamic-card", "index": n},
                )
            )
        ],
    )

    div_children.append(new_card)
    return div_children


@app.callback(
    Output({"type": "dynamic-title", "index": MATCH}, "children"),
    Input({"type": "dynamic-button", "index": MATCH}, "n_clicks"),
)
def update_card(n_clicks):
    print(n_clicks)
    return str(n_clicks)


app.run_server(mode="inline")
3 Likes