Dynamically created buttons firing their own callback on creation

I have button that I create dynamically {“type”: “btn”}.

I have a callback that targets all buttons: Input({“type”: “btn”, index: “ALL”}, n_clicks)
This callback gets triggered everytime I dynamically create such button of “type”: “btn”. This is not the desired behavior, I want it to be triggered whenever one of these buttons is actually clicked. Instead, it gets called on creation.

The component_id that triggers this callback is the very first button from the list: {“index”: 0", “type”: “btn”}.n_clicks. It does not get triggered by the latest button, it is always the very first button. The n_clicks value is unchanged, it returns a value that was already there.

What I tried is checking for whether the specific button that triggered the callback has n_clicks bigger than 0. Problem is, that dash.callback_context.triggered[0][“prop_id”] ALWAYS gives me the very first button of that type. That means that when the user actually clicks the first button and sets the n_clicks to more than zero, from that point, the callback will always pass as it always checks for the first button in the list for its n_clicks.

Adding buttons fires the callbacks as if someone clicked the button without changing the n_clicks. I cannot think of a way to ignore this callback when new button is instantiated.

I have also tried checking for n_clicks_timestamp, but that works just like before, when not clicked, it is simply None, but when the user clicks it, it is set to some value and then this value is always passed as a parameter whenever I add a new button, it is so frustrating.

What would you do in this situation? Apparently there is not such a thing as prevent_initial_call for dynamically created components, as that only targets components that were already in the app.layout().

Would you produce a working example that reproduces this behaviour? It’s unexpected, to me at least.

If not, and you do need to deal with this, one approach might be to store the n_clicks value(s) for the triggering button(s) in a dcc.Store, compare actual button n_clicks to the stored n_clicks.

Something like this in the layout

...
dcc.Store(id='btnclickstore'),
...

And something along these lines in the callback:

@app.callback(
    Output("btnclickstore", "data"),
    ... # other outputs,
    Input({“type”: “btn”, index: “ALL”}, n_clicks),
    State("btnclickstore", "data"),
    ... # other inputs
)
def btnclick(btnclicks, btnclickstore, ...):
    if (... compare if btnclicks equal to btnclickstore...):
        raise PreventUpdate

    ...
    return btnclicks, ... 

That helped, thanks :slight_smile: