BERNARD FIRANSKI
BERNARD FIRANSKI

Reputation: 1

How do I manage pathname prefixes in Plotly Dash for multiple pages?

I have a multipage Dash app using Python Plotly. The app consists of a home page hosting the navbar, a map page and 2 plot pages. The whole app is to be hosted on a server that requires a particular path prefix using:

dash.register_page(__name__,    
    requests_pathname_prefix="/app/SWAPIT/",
    routes_pathname_prefix="/app/SWAPIT/"
)

The home page works and I can navigate to the map page, but the plot pages give the 404 Not Found error despite the fact that all 3 pages use the same prefixes and have the same hrefs in the navbar code.

The code tree is as follows:

main
  -app.py
  -navbar.py
  pages
   -map.py
   -page_1.py
   -page_2.py

When I hover the cursor the link shows as localhost:8080/app/SWAPIT/... Each link looks correct so I cannot figure out what I'm doing wrong. I have created multipage apps with the various examples found online, but none of them use pathname prefixes, which is where I get confused. How do I apply the prefix? Is it included in navbar hrefs or not?

main app code:

NAVBAR = create_navbar()
# To use Font Awesome Icons
FA621 = "./all.css"
APP_TITLE = "Multipage Dash App"
(__name__, )
app = dash.Dash(
    __name__,
    suppress_callback_exceptions=True,
    external_stylesheets=[
        dbc.themes.LUX,  # Dash Themes CSS
        FA621,  # Font Awesome Icons CSS
    ],
    title=APP_TITLE,
    use_pages=True,  # New in Dash 2.7 - Allows us to register pages
    requests_pathname_prefix="/app/SWAPIT/",
    routes_pathname_prefix="/app/SWAPIT/"
)


app.layout = dcc.Loading(  # <- Wrap App with Loading Component
    id='loading_page_content',
    children=[
        html.Div(
            [
                NAVBAR,
                dash.page_container
            ]
        )
    ],
    color='primary',  # <- Color of the loading spinner
    fullscreen=True  # <- Loading Spinner should take up full screen
)

server = app.server


if __name__ == '__main__':
    # app.run_server(debug=False, host='0.0.0.0', port=8080)
    app.run(debug=False, host='0.0.0.0', port=8080)

Navbar code:

def create_navbar():
    navbar = dbc.NavbarSimple(
        children=[
            dbc.NavItem(
                dbc.NavLink("Map", active=True, href="/app/SWAPIT/map", target="_blank")
                ),

            dbc.NavItem(
                dbc.NavLink("Ambient Temperature", active=True, href="/app/SWAPIT/page_1", target="_blank")
                ),

            dbc.NavItem(
                dbc.NavLink("Gases", active=True, href="/app/SWAPIT/page_2", target="_blank")
                ),

            dbc.DropdownMenu(
                nav=True,
                in_navbar=True,
                label="Menu",
                align_end=True,
                children=[  # Add as many menu items as you need
                    dbc.DropdownMenuItem("Home", href='/'),
                    dbc.DropdownMenuItem(divider=True),
                    dbc.DropdownMenuItem("Map", href='/app/SWAPIT/map'),
                    dbc.DropdownMenuItem("Ambient Temperature", href='/app/SWAPIT/page_1'),
                    dbc.DropdownMenuItem("Gases", href='/app/SWAPIT/page_2'),
                ],
            ),
        ],
        brand='Home',
        brand_href="/app/SWAPIT/",
        # sticky="top",  # Uncomment if you want the navbar to always appear at the top on scroll.
        color="dark",  # Change this to change color of the navbar e.g. "primary", "secondary" etc.
        dark=True,  # Change this to change color of text within the navbar (False for dark text)
    )

    return navbar

Each page has the same prefix: I'm not bothering to show what's in the page because the contnet is not germane to my question and would just clutter things up.

# register this as a page in the app
dash.register_page(__name__,    
    requests_pathname_prefix="/app/SWAPIT/",
    routes_pathname_prefix="/app/SWAPIT/"
)

I have also tried in the navbar links (for example):

href='./pages/pages_1'

and

href='/app/SWAPIT/pages/page_1

Those don't work either. Any help is greatly appreciated!

Upvotes: 0

Views: 147

Answers (1)

ErikApption
ErikApption

Reputation: 1

I was able to get multi-page working in the nested folder example on https://github.com/AnnMarieW/dash-multi-page-app-demos with the following changes:

  1. Add url_base_pathname to dash.Dash
url_prefix = "/app/SWAPIT/"
app = dash.Dash(
    __name__,
    plugins=[dl.plugins.pages],
    external_stylesheets=[dbc.themes.BOOTSTRAP, dbc.icons.FONT_AWESOME],
    url_base_pathname=url_prefix
)

This seems to take care of paths and routes however the pages at this point are not aware of the prefix.

  1. Add prefix to links

page['path'] is not aware of the prefix - so each link needs to include the prefix as well.

href=url_prefix + page["path"]
  1. Running the example repo requires some pip package wizardry because some dash components are not compatible with recent flask versions. These are my requirements
dash >=2.18.1
dash-bootstrap-components >=1.6.0
Flask==2.1.0
Werkzeug==2.2.2

Also I did not have to do any change on the register_page. Each file has only register_page(__name__, icon="fas fa-chart-bar")

Upvotes: 0

Related Questions