I have a very simple application as follows:
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State
external_stylesheets = [
'https://codepen.io/chriddyp/pen/bWLwgP.css',
'https://codepen.io/chriddyp/pen/brPBPO.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.config.suppress_callback_exceptions = True
def generate_dropdown(id):
values = [dict(label=x, value=x) for x in ['A', 'B', 'C']]
return dcc.Dropdown(id=id, options=values, value=None)
layout = html.Div([
html.H5('TEST'),
generate_dropdown('dropdown_1'),
html.Div(id='dropdown_2_placeholder'),
html.Div(id='dropdowns_value')
])
app.layout = layout
@app.callback(
Output('dropdown_2_placeholder', 'children'),
[Input('dropdown_1', 'value')])
def render_dropdown2(value):
if value is not None:
return generate_dropdown('dropdown_2')
else:
return None
@app.callback(
Output('dropdowns_value', 'children'),
[Input('dropdown_2', 'value')],
[State('dropdown_1', 'value')])
def render_dropdown_values(value2, value1):
if value1 is not None and value2 is not None:
return '%s %s' % (value1, value2)
else:
return None
if __name__ == '__main__':
app.run_server(debug=True)
Everything seems to be ok. Please notice that dropdown_2
is being created dynamically when dropdown_1
value changes and dropdown_2
is an input for render_dropdown_values
callback - itās dynamic thatās the whole purpose of having suppress_callback_exceptions
Unfortunately when I try to use this app in a multi-page app (with dcc.Link & dcc.Location) i see a following error message in a browser console:
Uncaught (in promise) ReferenceError: An invalid input object was used in an `Input` of a Dash callback. The id of this object is `dropdown_2` and the property is `value`. The list of ids in the current layout is `[url, header-container, page-container, dropdown_1, dropdown_2_placeholder, dropdowns_value]` at dash_renderer.min.js:1 at Array.map (<anonymous>) at K (dash_renderer.min.js:1) at dash_renderer.min.js:1 at Array.forEach (<anonymous>) at dash_renderer.min.js:1 at <anonymous>
It seems that in this case dash_renderer is trying to invoke/validate all the callbacks defined in an sub-app.
[EDIT]:
In order to make it easier to reproduce I took an example of multipage app from here URL Routing and Multiple Apps | Dash for Python Documentation | Plotly and replaced page_2 layout with above:
import dash
import dash_core_components as dcc
import dash_html_components as html
print(dcc.__version__) # 0.6.0 or above is required
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
# Since we're adding callbacks to elements that don't exist in the app.layout,
# Dash will raise an exception to warn us that we might be
# doing something wrong.
# In this case, we're adding the elements through a callback, so we can ignore
# the exception.
app.config.suppress_callback_exceptions = True
app.layout = html.Div([
dcc.Location(id='url', refresh=False),
html.Div(id='page-content')
])
index_page = html.Div([
dcc.Link('Go to Page 1', href='/page-1'),
html.Br(),
dcc.Link('Go to Page 2', href='/page-2'),
])
page_1_layout = html.Div([
html.H1('Page 1'),
dcc.Dropdown(
id='page-1-dropdown',
options=[{'label': i, 'value': i} for i in ['LA', 'NYC', 'MTL']],
value='LA'
),
html.Div(id='page-1-content'),
html.Br(),
dcc.Link('Go to Page 2', href='/page-2'),
html.Br(),
dcc.Link('Go back to home', href='/'),
])
@app.callback(dash.dependencies.Output('page-1-content', 'children'),
[dash.dependencies.Input('page-1-dropdown', 'value')])
def page_1_dropdown(value):
return 'You have selected "{}"'.format(value)
def generate_dropdown(id):
values = [dict(label=x, value=x) for x in ['A', 'B', 'C']]
return dcc.Dropdown(id=id, options=values, value=None)
page_2_layout = html.Div([
html.H5('TEST'),
generate_dropdown('dropdown_1'),
html.Div(id='dropdown_2_placeholder'),
html.Div(id='dropdowns_value')
])
@app.callback(
dash.dependencies.Output('dropdown_2_placeholder', 'children'),
[dash.dependencies.Input('dropdown_1', 'value')])
def render_dropdown2(value):
if value is not None:
return generate_dropdown('dropdown_2')
else:
return None
@app.callback(
dash.dependencies.Output('dropdowns_value', 'children'),
[dash.dependencies.Input('dropdown_2', 'value')],
[dash.dependencies.State('dropdown_1', 'value')])
def render_dropdown_values(value2, value1):
if value1 is not None and value2 is not None:
return '%s %s' % (value1, value2)
else:
return None
# Update the index
@app.callback(dash.dependencies.Output('page-content', 'children'),
[dash.dependencies.Input('url', 'pathname')])
def display_page(pathname):
if pathname == '/page-1':
return page_1_layout
elif pathname == '/page-2':
return page_2_layout
else:
return index_page
# You could also return a 404 "URL not found" page here
if __name__ == '__main__':
app.run_server(debug=True)