Dash rendering order

Hello, I have the following Dash app whose layout is dependent of the data it gets initially,

if __name__ == '__main__':
    path = "/mypath/"
    data_manager.load_all_data(path)
    app.layout = get_layout
    app.run_server(debug=False, use_reloader=False)

and the paths and layouts are then created dynamically based on the data as we can see in the generate_sub_menus and render_page_content_callback

from mainwrapper import app

def generate_sub_menus():
    reports = data_manager.get_full_df()
    all_menus = []
    for report in reports:
        tab_links = []
        for tab_page in reports[report]:
            tab_links.append(dbc.NavLink(tab_page, href=f"/{report}/{tab_page}",
                                         id={"type": "nav_link", "report_name": report, "tab_page": tab_page}))
        menu = [
            html.Li(
                dbc.Row(
                    [
                        dbc.Col(report.capitalize()),
                        dbc.Col(
                            html.I(className="fas fa-chevron-right"),
                            width="auto",
                        ),
                    ],
                    className="my-2",

                ),
                style={"cursor": "pointer"},
                id={"type": "submenu-toggle", "report_name": report},
            ),
            dbc.Collapse(
                children=tab_links,
                id={"type": "submenu-collapse", "report_name": report},
            )
        ]
        all_menus = all_menus + menu
    return all_menus



def get_sidebar():
    return html.Div(
    [
        html.Div(
            [
                html.H2("Report", style={"color": "black"}),
            ],
            className="sidebar-header",
        ),
        html.Br(),
        html.Div(style={"border-top": "2px solid black"}),
        html.Br(),
        # nav component
        dbc.Nav(generate_sub_menus(), vertical=True),
    ],
    style=SIDEBAR_STYLE,
    id="sidebar",
)





def get_layout():
    return html.Div(
        [


            get_sidebar(),
            html.Div(

                className="content",
                style=CONTENT_STYLE,
                id="page-content",

            ),
            dcc.Location(id="url"),

            # dcc.Store(id='tables-store'),  # CACHING ATTEMPT
        ]
    )



@app.callback(
    Output({'type': 'submenu-collapse', 'report_name': MATCH}, 'is_open'),
    [Input({'type': 'submenu-toggle', 'report_name': MATCH}, 'n_clicks')],
    [State({'type': 'submenu-collapse', 'report_name': MATCH}, 'is_open')],
)
def toggle_collapse(n, is_open):
    if n:
        return not is_open
    return is_open


@app.callback(
    Output({'type': 'submenu-toggle', 'report_name': MATCH}, 'className'),
    [Input({'type': 'submenu-collapse', 'report_name': MATCH}, 'is_open')],
)
def set_navitem_class(is_open):
    if is_open:
        return "open"
    return ""



@app.callback(Output("page-content", "children"), [Input("url", "pathname")],
              prevent_initial_call=True)
def render_page_content(pathname):
    full_df = data_manager.get_full_df()

    if pathname and pathname.startswith("/"):
        pathname = pathname[1:]

    path_segments = pathname.split('/')
    if pathname == "/":
        first_report = next(iter(full_df))
        first_tab = next(iter(full_df[first_report]))

        return tab_page.tab_page_layout(first_report, first_tab)

    return tab_page.tab_page_layout(path_segments[0], path_segments[1])


The thing is that if I do for example



app.layout = html.Div( 
[


            get_sidebar(),
            html.Div(

                className="content",
                style=CONTENT_STYLE,
                id="page-content",

            ),
            dcc.Location(id="url"),

            # dcc.Store(id='tables-store'),  # CACHING ATTEMPT
        ]
    )

Then the the sidebar will be empty as it seems the data wont be loaded and generate_sub_menus will then get empty data.
The page content will be display though.

I know that with the latter, the dash layout is computed once and if I serve the app.layout with a function like the first way, then it will be dynamic, but I dont understand why in the non-function way the data is not loaded when its literally the first thing the program does in its entry point. Also I must add that I have another file called mainwrapper.py where i import the app, as you can see

Are you trying to make the layout different between one user session and another?

Each user will be presented a page with an input text box and will provide a path, then the dash layouts will be loaded accordingly to the data that is in the path (this is for an internal tool). The layout is basically the same, but the data in them will be different, the number of tabs/pages is dependent on the data and thus on the input of the user. I want it to support two or more users at the same time

I don’t think you can do this in quite this way - app.run_server() is executed when you start the server, but it is not executed each time a user navigates to the URL. (One instance of run_server() may serve many simultaneous browser sessions).

To get per-user behaviour, generate_sub_menus() (possibly more) needs instead to be executed within a callback that is triggered when a user loads the page or fills in the text box. The callback can customise the screen layout by Output to the ‘children’ property of, say, a div. And you will need to organise it so that browser sessions do not modify global variables.

(Part 4. Sharing Data Between Callbacks | Dash for Python Documentation | Plotly)

1 Like