Looking for simple way to change pages based on conditions

I am looking for a way to check that certain conditions are met before the page changes. My callback is supposed to check that two fields have been entered, if not it gives an alert pop up. If they have been entered, it takes the data, stores it, and goes to the next page. All of this happens when a button has been clicked.

I initially had the button click have an href that directed to the page, but it wouldn’t check for the error that way. I was thinking to do Output(‘data-button’, ‘href’) but that didn’t seem to work.

I’m using the register pages method.

This is my layout and the callback I have set up so far:

layout = html.Div([
        dbc.Row([
            html.Center([
                html.H3('Select a Region and then an Engine')
            ])
        ]),
        dbc.Row([
            html.Center([
                dcc.Dropdown(
                    id='region-drop',
                    options=df.region.unique(),
                    placeholder='Region',
                dcc.Dropdown(
                    id='engine-drop',
                    options=[],
                    placeholder='Engine',
            ])
        ]),

        dbc.Row([
            html.Div([
                html.Center(
                    html.H3(
                        'What meeting is this for?'),
                dbc.RadioItems(
                    options=[
                        {'label': current_month, 'value': current_month},
                        {'label': next_month, 'value': next_month},
                    ],
                    value=current_month,
                    id='report-options',
                    inline=True,
                )
            ])
        ]),

        dbc.Row([
            html.Center([
                html.H3('Choose an End Date'),
                html.P('(Gets data going back a year from chosen date.)')
            ])
        ]),

        dbc.Row([
            html.Center([
                dcc.Input(
                    type='datetime-local',
                    step='60',
                    min='2000-01-01T00:00',
                    max=datetime.now(),
                    value=datetime.now(),
                    id='start-date'
                )
            ])
        ]),

        dbc.Row([
            html.Center([
                dbc.Button(
                    'Generate Graph',
                    id='data-button',
                    n_clicks=0,
                    color='secondary',
                    href='graph'
                )
            ])
        ]),

        dbc.Row([
            html.Center([
                dbc.Alert(
                    children=["Did not select all required information."],
                    color='danger',
                    id='error-alert',
                    is_open=False,
                )
            ])
        ])
])


@callback(
    Output('store', 'data'),
    Output('error-alert', 'is_open'),
    State('error-alert', 'is_open'),
    Input('data-button', 'n_clicks'),
    State('engine-drop', 'value'),
    State('start-date', 'value'),
    State('region-drop', 'value'),
    State('report-options', 'value')
)
def query_data(is_open, n1, engine, date, region, report):
    if n1:
        if engine == None or region == None:
            store = {}
            return store, not is_open, 
        else: 
            data = sqlc.get_data_for_app(region=region, engine=engine, end_date=date)
            data = wr.get_past_year(df=data, end_date=date)
            store = {"df": data.to_dict('records'), "date": date, "engine": engine, "report": report}
            return store, is_open,
    
return dash.no_update, dash.no_update,

My dcc.Store is on a different page.

Hello @bpolasek,

You should be able to do this, you shouldnt need to reference the open, have the outputs be (data, is_open, href), upon the right info, fill (info, False, target dest). On bad info, return (no_update, True, no_update).

Like this?

@callback(
    Output('store', 'data'),
    Output('error-alert', 'is_open'),
    Output('data-button', 'href'),
    State('error-alert', 'is_open'),
    Input('data-button', 'n_clicks'),
    State('engine-drop', 'value'),
    State('start-date', 'value'),
    State('region-drop', 'value'),
    State('report-options', 'value')
)
def query_data(is_open, n1, engine, date, region, report):
    if n1:
        if engine == None or region == None:
            store = {}
            return store, not is_open, dash.no_update
        else: 
            data = sqlc.get_data_for_app(region=region, engine=engine, end_date=date)
            data = wr.get_past_year(df=data, end_date=date)
            store = {"df": data.to_dict('records'), "date": date, "engine": engine, "report": report}
            return store, is_open, 'graph'
    return dash.no_update, dash.no_update, dash.no_update

Not sure what I’m missing because it’s not working :confused:

Try this:

@callback(
    Output('store', 'data'),
    Output('error-alert', 'is_open'),
    Output('data-button', 'pathname'),
    Input('data-button', 'n_clicks'),
    State('engine-drop', 'value'),
    State('start-date', 'value'),
    State('region-drop', 'value'),
    State('report-options', 'value')
)
def query_data(n1, engine, date, region, report):
    if n1:
        if engine == None or region == None:
            store = {}
            return store, True, dash.no_update
        else: 
            data = sqlc.get_data_for_app(region=region, engine=engine, end_date=date)
            data = wr.get_past_year(df=data, end_date=date)
            store = {"df": data.to_dict('records'), "date": date, "engine": engine, "report": report}
            return store, False, '/graph'
    return dash.no_update, dash.no_update, dash.no_update

Still not changing the page. This is how the button should be set up correct?

        dbc.Row([
            html.Center([
                dbc.Button(
                    'Generate Graph',
                    id='data-button',
                    n_clicks=0,
                    color='secondary',
                )
            ])
        ]),

I’ve also included variations of href=‘’ or href=‘/’ or just not including it like seen above.

It needs to be pathname, not href, href is the full path, you are only passing the last bit.

Are you getting any errors?

The dash-bootstrap-component is giving an error that pathname is not kwarg.

Previously before implementing this, href=‘graph’ would redirect to the page. But I just need to implement an error message in case a user doesn’t select all the necessary info. dcc.Dropdown doesn’t have a required argument so I was trying to set an alert if they are empty.

Sorry, you need to add a location element, once you do that, target the pathname of that id, and it should work.

So dcc.Location? Does that need to be in the button or separately? I was looking at that before but I thought it was for the old way to create multi-page apps?

It is used in any scenario where you want to reference or alter the href of the page.

It is not a button, just add it to the current page’s layout.

Awesome thank you!