I’ve got a small minimal example to share. Really could use some help on this because I don’t know how to structure my app to get around it. I’ve read everything I can on the forum but I just don’t understand the app, the server wrapping the app, and how I can just put my callbacks where I want them and still have them function.
My expectation:
On URL change:
app.layout renders and loads data into dcc.Store component id=‘f_app_loaded’
THEN
pages/login detects that ‘f_app_loaded’ changed and does its callback to populate the change
Here’s what happens:
app.layout renders and loads data into dcc.Store component id=‘f_app_loaded’
pages/login does nothing.
If I add a 2 second delay to the app callback, then the page callback detects the callback properly.
I don’t understand how to set up the app, do I really have to put ALL of my callbacks on one .py file? That sounds like a nightmare to manage.
This is main.py
import flask
import dash
from dash import Dash, html, dcc, callback, Output, Input
import dash_bootstrap_components as dbc
import os
import time
server = flask.Flask(__name__)
app = Dash(__name__,
server=server
, external_stylesheets=[
dbc.themes.BOOTSTRAP
]
,assets_folder=os.getcwd() + '/assets'
, use_pages=True
, eager_loading=False
)
app.layout = html.Div([
# dcc.Location(refresh="callback-nav", id='app_url_location')
dcc.Location(refresh='', id='app_url_location')
, dcc.Store(id='f_app_loaded', storage_type='session')
,dash.page_container
])
@callback(
Output("f_app_loaded", "data")
,Input("app_url_location", 'pathname')
)
def app_level_checks(app_level_path):
print("load some data to trigger the page level callback (it doesn't work)!")
#why does WAITING 2 seconds work?!
#time.sleep(2)
return {}
if __name__ == '__main__':
server.run(host='localhost', port=8082, debug=False)
This is pages/login.py
import dash
from dash import html,State,dcc,callback,Input, Output, ALL, ctx, Patch, MATCH
from dash.exceptions import PreventUpdate
import dash_bootstrap_components as dbc
dash.register_page(__name__, path='/')
pname = __name__.split(".")[-1]
def layout(**kwargs):
print("launch layout for login page")
ly= html.Div(
[
dcc.Location(id='page_url_location')
,html.Div("login content that should be overwritten by the callback that will never trigger")
]
, id='page-content'
, **kwargs
)
return ly
@callback(
Output('page-content','children')
,Input("f_app_loaded", "data")
#,Input("f_app_loaded", "modified_timestamp")
#,Input("page-content","children")
#,Input("page_url_location","path")
#,prevent_initial_call=True
)
def page_layout_cb(data
#,mod_ts
#,children
#,url_p
):
trg_id = ctx.triggered_id
if not trg_id:
print("I didn't get the triggered ID I'm owed")
raise PreventUpdate
print(f"dash_login page page_layout_cb from {trg_id}")
components = [
html.H1("Welcome to a broken app!")
,html.P("Please log in to continue")
]
return components