App.validation_layout doesn't work?

I tried the example with app.validation_layout from the documentation.

I modified the provided example by adding dbc.Button(id='test-Button') to app.validation_layout and then using the same button as an input in the display_value(value, n_clicks) callback (page 2) and also specified prevent_initial_call=True for that callback.

From my understanding this should prevent the initial layout validation error. But it does not. What am I missing?

Full code:

import dash
import dash_core_components as dcc
import dash_html_components as html
import dash_bootstrap_components as dbc
from dash.dependencies import Input, Output, State

import flask

app = dash.Dash(__name__)

url_bar_and_content_div = html.Div([
    dcc.Location(id='url', refresh=False),
    html.Div(id='page-content')
])

layout_index = html.Div([
    dcc.Link('Navigate to "/page-1"', href='/page-1'),
    html.Br(),
    dcc.Link('Navigate to "/page-2"', href='/page-2'),
])

layout_page_1 = html.Div([
    html.H2('Page 1'),
    dcc.Input(id='input-1-state', type='text', value='Montreal'),
    dcc.Input(id='input-2-state', type='text', value='Canada'),
    html.Button(id='submit-button', n_clicks=0, children='Submit'),
    html.Div(id='output-state'),
    html.Br(),
    dcc.Link('Navigate to "/"', href='/'),
    html.Br(),
    dcc.Link('Navigate to "/page-2"', href='/page-2'),
])

layout_page_2 = html.Div([
    html.H2('Page 2'),
    dcc.Dropdown(
        id='page-2-dropdown',
        options=[{'label': i, 'value': i} for i in ['LA', 'NYC', 'MTL']],
        value='LA'
    ),
    html.Div(id='page-2-display-value'),
    html.Br(),
    dcc.Link('Navigate to "/"', href='/'),
    html.Br(),
    dcc.Link('Navigate to "/page-1"', href='/page-1'),
])

# index layout
app.layout = url_bar_and_content_div

# "complete" layout
app.validation_layout = html.Div([
    url_bar_and_content_div,
    layout_index,
    layout_page_1,
    layout_page_2,
    dbc.Button(id='test-Button')
])


# Index callbacks
@app.callback(Output('page-content', 'children'),
              Input('url', 'pathname'))
def display_page(pathname):
    if pathname == "/page-1":
        return layout_page_1
    elif pathname == "/page-2":
        return layout_page_2
    else:
        return layout_index


# Page 1 callbacks
@app.callback(Output('output-state', 'children'),
              Input('submit-button', 'n_clicks'),
              State('input-1-state', 'value'),
              State('input-2-state', 'value'))
def update_output(n_clicks, input1, input2):
    return ('The Button has been pressed {} times,'
            'Input 1 is "{}",'
            'and Input 2 is "{}"').format(n_clicks, input1, input2)


# Page 2 callbacks
@app.callback(Output('page-2-display-value', 'children'),
              Input('page-2-dropdown', 'value'),
              Input('test-button', 'n_clicks'),
              prevent_initial_call=True)
def display_value(value, n_clicks):
    print('display_value')
    return 'You have selected "{}"'.format(value)


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

Packages:

dash==2.0.0
dash-bootstrap-components==1.0.0
dash-bootstrap-templates==1.0.1
dash-core-components==2.0.0
dash-extensions==0.0.51
dash-html-components==2.0.0
dash-renderer==1.9.1
dash-table==5.0.0
dash-tabulator==0.4.2

Hi @sislvacl

I think the problem is that the id is 'test-Button' here:

dbc.Button(id='test-Button')

and 'test-button' in the callback:

Input('test-button', 'n_clicks'),

oops that was a little awkward. You are right @AnnMarieW !

Anyways, I still have a problem with layout validation. Unfortunately, I’m not able to reproduce the error with a shareable example. The error I’m getting is the following:

A nonexistent object was used in an `Input` of a Dash callback. 
The id of this object is `test-button` and the property is `n_clicks`. 
The string ids in the current layout are: [list_of_all_the_IDs...]

I’m getting this error in a multi page app where the test-button is not present in page2 initial layout (the button is generated dynamically).

The button is used as in Input in two callbacks - one of them is normal, the other is long_callback). Both callbacks have prevent_initial_call=True.

I’m getting the error only when opening localhost:5000/page2 (not when opening localhost:5000/page1).

The error is being raised by the long_callback, not by the normal callback.

Any ideas about what I could try to trace the error?

@sislvacl Haha - I thought that might be a typo :smiley:

hmm, it’s hard to trace without a MWE. I can’t duplicate the error. Can you modify this example to make it generate the error you are seeing?


from dash import Dash, dcc, html, Input, Output, State, no_update
from dash.long_callback import DiskcacheLongCallbackManager

import dash_bootstrap_components as dbc

## Diskcache
import diskcache
cache = diskcache.Cache("./cache")
long_callback_manager = DiskcacheLongCallbackManager(cache)
import time


app = Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])


url_bar_and_content_div = html.Div([
    dcc.Location(id='url', refresh=False),
    html.Div(id='page-content')
])

layout_index = html.Div([
    dcc.Link('Navigate to "/page-1"', href='/page-1'),
    html.Br(),
    dcc.Link('Navigate to "/page-2"', href='/page-2'),
])

layout_page_1 = html.Div([
    html.H2('Page 1'),

    dcc.Input(id='input-1-state', type='text', value='Montreal'),
    dcc.Input(id='input-2-state', type='text', value='Canada'),
    html.Button(id='submit-button', n_clicks=0, children='Submit'),
    html.Div(id='output-state'),
    html.Br(),
    dcc.Link('Navigate to "/"', href='/'),
    html.Br(),
    dcc.Link('Navigate to "/page-2"', href='/page-2'),
])

long_callback =  html.Div(
    [
        html.Div([html.P(id="paragraph_id", children=["Button not clicked"])]),
        html.Button(id="add-button", children="Add long callback"),
        html.Div(id="add-button-div")
    ]
)

layout_page_2 = html.Div([
    html.H2('Page 2'),

    dcc.Dropdown(
        id='page-2-dropdown',
        options=[{'label': i, 'value': i} for i in ['LA', 'NYC', 'MTL']],
        value='LA'
    ),
    long_callback,
    html.Div(id='page-2-display-value'),
    html.Br(),
    dcc.Link('Navigate to "/"', href='/'),
    html.Br(),
    dcc.Link('Navigate to "/page-1"', href='/page-1'),
])

# index layout
app.layout = url_bar_and_content_div

# "complete" layout
app.validation_layout = html.Div([
    url_bar_and_content_div,
    layout_index,
    layout_page_1,
    layout_page_2,
    html.Button(id="test-button", children="Run Job!")
])


# Index callbacks
@app.callback(Output('page-content', 'children'),
              Input('url', 'pathname'))
def display_page(pathname):
    if pathname == "/page-1":
        return layout_page_1
    elif pathname == "/page-2":
        return layout_page_2
    else:
        return layout_index


# Page 1 callbacks
@app.callback(Output('output-state', 'children'),
              Input('submit-button', 'n_clicks'),
              State('input-1-state', 'value'),
              State('input-2-state', 'value'))
def update_output(n_clicks, input1, input2):
    return ('The Button has been pressed {} times,'
            'Input 1 is "{}",'
            'and Input 2 is "{}"').format(n_clicks, input1, input2)


# Page 2 callbacks
@app.callback(Output('page-2-display-value', 'children'),
              Input('page-2-dropdown', 'value'),
              Input('test-button', 'n_clicks'),
              prevent_initial_call=True)
def display_value(value, n_clicks):
    return 'You have selected "{}"'.format(value)


@app.callback(
    Output("add-button-div", "children"),
    Input("add-button", "n_clicks"),
    prevent_initial_call=True,
)
def add_button(n):
    if n is not None:
        return  html.Button(id="test-button", children="Run Job!")


@app.long_callback(
    output=Output("paragraph_id", "children"),
    inputs=Input("test-button", "n_clicks"),
    manager=long_callback_manager,
    prevent_initial_call=True
)
def callback(n_clicks):
    time.sleep(2.0)
    return [f"Clicked {n_clicks} times"]



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