I have two sliders inside a html.Div. when i change the children of the Div, it fire a callback which have a slider as input, why. This is the example code:
import dash
import dash_html_components as html
import dash_core_components as dcc
import dash_bootstrap_components as dbc
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.config.suppress_callback_exceptions=True
app.layout = html.Div([
dbc.Button("Add slider",id="button"),
html.Div([
],id='range-sliders'),
html.Div(id='output-container-range-slider')
])
@app.callback(
Output('range-sliders','children'),
[Input('button','n_clicks')],
[State('range-sliders','children')]
)
def addslider(click,children):
print("2")
if children:
if click:
children[0]['props']['value'] = [0,20]
return children
else:
children.append(html.Div([
dcc.RangeSlider(
id='range1',
min=0,
max=20,
step=0.5,
value=[5, 15]
),
dcc.RangeSlider(
id='range2',
min=0,
max=20,
step=0.5,
value=[5, 15]
)]))
return children
@app.callback(
dash.dependencies.Output('output-container-range-slider', 'children'),
[dash.dependencies.Input('range1', 'value')])
def update_output(value):
print("1")
return 'You have selected "{}"'.format(value)
if __name__ == '__main__':
app.run_server()
Note: when I click in button, the ouput show:
2
1
2
1
2
1
You can use “callback context” in order to fire the callback when a specific property is triggered. It uses the global variable dash.callback_context which is available in callbacks to access the list of changed properties within a callback. You can learn more about it in the Dash documentation FAQs here.
I’ve modified your code below to use callback context to only fire the children after you press the button, I think that’s what your post above is looking for. Let me know if that’s on point. Cheers.
import dash
import dash_html_components as html
import dash_core_components as dcc
import dash_bootstrap_components as dbc
from dash.dependencies import Input, Output, State
import pdb
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.config.suppress_callback_exceptions = True
app.layout = html.Div([
html.Div(id='test'),
dbc.Button("Add slider", id="button"),
html.Div([
], id='range-sliders'),
html.Div(id='output-container-range-slider')
])
@app.callback(
Output('range-sliders', 'children'),
[Input('button', 'n_clicks')],
[State('range-sliders', 'children')]
)
def addslider(click, children):
print("2")
if children:
if click:
children[0]['props']['value'] = [0, 20]
return children
else:
children.append(html.Div([
dcc.RangeSlider(
id='range1',
min=0,
max=20,
step=0.5,
value=[5, 15]
),
dcc.RangeSlider(
id='range2',
min=0,
max=20,
step=0.5,
value=[5, 15]
)]))
return children
@app.callback(
Output("output-container-range-slider", "children"),
[Input("button", "n_clicks"),
Input("range-sliders", "children")],
)
def update_output(clicks, value):
print("1")
ctx = dash.callback_context
if "range-sliders.children" in ctx.triggered[0]['prop_id']:
return 'You have selected "{}"'.format(value[0]['props']['children'][0]['props']['value'])
if __name__ == '__main__':
app.run_server()
import dash
from dash.dependencies import Input, Output, State
import dash_html_components as html
import dash_core_components as dcc
import ast
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.config.suppress_callback_exceptions=True
app.layout = html.Div([
html.Button('Add a slider', id='button', n_clicks=0),
html.Div(children=[],id='slider-container'),
# this is a hack: include a hidden dcc component so that
# dash registers and serve's this component's JS and CSS
# libraries
dcc.Input(style={'display': 'none'})
])
@app.callback(
Output('slider-container', 'children'),
[Input('button', 'n_clicks')],
[State('slider-container','children')])
def add_sliders(n_clicks,children):
print("1")
#global children
if children:
if n_clicks:
print(children)
return children
else:
for i in range(10):
children.append(html.Div(
[html.Div([
html.Div(dcc.RangeSlider(
id='slider-{}'.format(i),
min=0,
max=20,
step=0.5,
value=[5, 15]
),),
html.Label(id='output-{}'.format(i), style={'marginTop': 30})
])]
))
return children
def generate_input():
c = [Input('slider-{}'.format(i), 'value') for i in range(10)]
return tuple(c)
def generate_output():
c = [Output('output-{}'.format(i), 'children') for i in range(10)]
return tuple(c)
@app.callback(
[a for a in generate_output()],
[a for a in generate_input()])
def update_output(*slider_i_value):
print("2")
ctx = dash.callback_context
if ctx.triggered:
print(ctx.triggered)
print("3")
return slider_i_value
if __name__ == '__main__':
app.run_server()
When you start app, Update_output is called and if you change a value of a range-slider Update_output save the last call and is called twice. This is an example but i need this for a proyect. And it’s possible return only a value when you have more than one outputs? and return value to specific Output.