Dynamically created item is absent from Dash.layout and never trigger callbacks

PROBLEM: callbacks for dynamically created buttons do not register

  • added a close-to-minimal example of dynamically creating buttons
  • dynamic buttons get dynamic ID
  • callbacks registered dynamically using this ID
  • callbacks are present in app.callback_map - checked with debugger
  • however dynamic button is missing from app.layout

QUESTIONS:

  • can I update app.layout to involve the dynamically added components?
  • would this fix the callback issue?
import dash
import dash_html_components as html
from dash.dependencies import Input, Output, State

app = dash.Dash(__name__)

app.layout = html.Div(children=[
    html.H1(children='Dynamic content with callback'),
    html.Div(id="btn-wrapper", children=[html.Button("Click me", id="btn-0")]),
])


def log_click(n_clicks, children):
    print("Dynamic button was clicked")
    return children


def on_click(n_clicks, children):
    btn_id = "btn-%d" % n_clicks
    children.append(html.Button("%s" % btn_id, id=btn_id))
    # add callback to dynamically created button
    app.callback(prevent_initial_call=True,
                 output=Output(btn_id, 'children'),
                 inputs=[Input(btn_id, 'n_clicks')],
                 state=[State(btn_id, 'children')]
                 )(log_click)
    return children


app.callback(prevent_initial_call=True,
    output=Output('btn-wrapper', 'children'),
    inputs=[Input('btn-0', 'n_clicks')],
    state=[State('btn-wrapper', 'children')]
)(on_click)


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