@Emil,
It’s not perfect, but does convey the thinking behind being dynamic.
from dash import Dash, html, Output, Input, State, dcc
from flask import Flask
server = Flask(__name__)
app = Dash(server=server,
external_scripts=[
{'src':"http://127.0.0.1:8050/assets/myButtons.js"}],
suppress_callback_exceptions=True,
prevent_initial_callbacks=True)
app.layout = html.Div([
dcc.Store(id='newButton', storage_type='local'),
html.Button("Add", id="add"),
html.Div([], id="container"),
])
@server.route("/assets/myButtons.js", methods=['GET'])
def myButtons():
maps = app.callback_map
btns = ['btn'+str(i) for i in range(20)]
inputData = []
for info in maps:
inputData.append(maps[info]['inputs'][0]['id'])
for btn_id in btns:
if not btn_id in inputData:
app.clientside_callback(
"""
function(x,y) {
alert(y + ' clicked ' + x + ' times')
return y
}
""",
Output(btn_id, 'children'),
Input(btn_id, 'n_clicks'),
State(btn_id,'children')
)
return "Your buttons have been added"
@app.callback(Output("container", "children"),
Input("add", "n_clicks"),
State("container", "children")
)
def add(n_clicks, children):
btn_id = f"btn{n_clicks}"
log_id = f"log{n_clicks}"
children.append(html.Button(f"Button number {n_clicks}", id=btn_id))
children.append(html.Div(id=log_id))
return children
if __name__ == '__main__':
app.run(debug=True)
Potentially, on the first load it would all the buttons and the events associated with it. Even on the first load, it knows that something is there and is being triggered but it doesnt quite work. On the second load, everything works as expected.
The point of dynamic buttons is being able to pass in arguments and add buttons and functionality without having to go into the app to make the changes. Not add the buttons this way of this example.
Also, please note, your example worked first by adding the callback, once you refreshed, it would have worked like my second picture up to what you had added.