Sharing examples of navigation without refreshing the page when URL is updated in a callback in Dash 2.9.2!

:tada: New in dash 2.9.2

It’s now possible to update the URL in a callback to navigate to a new page of a multi-page app without refreshing the page


:partying_face: NEW – dcc.Location(refresh="callback-nav") - No page refresh!


callback-nav






:stuck_out_tongue_closed_eyes: OLD – dcc.Location(refresh=True) Note the screen flash:

To see these examples (and more!) check out:


Background

With Dash Pages, the routing callback is under-the-hood, which reduces the amount of boilderplate code you need to write.
The best way to navigate is to use components such as the dcc.Link or dbc.Button. When the user clicks on these
links, it will navigate to the new page without refreshing the page, making the navigation very fast. And the best part? No callback required!

This works well when you have static links. However, at times, you may want to navigate based on an input field, ropdown, or clicking on a figure etc. There are two options:

  1. Update href of dcc.Location in a callback. Not recommended in Dash<2.9.2 because it refreshes the page.
  2. Update the link in a callback. Best practice!

:tada: New in dash 2.9.2 dcc.Location(refresh="callback-nav") - navigate without refreshing the page.

Here’s an example of navigating to a new page when clicking on a figure:

- app.py
- pages
|-- flight_status.py
|-- home.py

app.py

from dash import Dash, dcc, page_container
import dash_bootstrap_components as dbc

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

navbar = dbc.NavbarSimple(
    dbc.Button("Home", href="/", color="secondary", className="me-1"),
    brand="Multi Page App Demo",
    color="primary",
    dark=True,
    className="mb-2",
)

app.layout = dbc.Container(
    [
        dcc.Location(id="url", refresh="callback-nav"),
        navbar, page_container,
    ], fluid=True
)

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

pages/home.py

import dash
from dash import dcc, html, Input, Output, callback, register_page
import plotly.express as px
import pandas as pd

register_page(__name__, path="/")

df_airports = pd.read_csv(
    "https://raw.githubusercontent.com/plotly/datasets/master/2011_february_us_airport_traffic.csv"
)
fig = px.scatter_mapbox(
    df_airports,
    lat="lat",
    lon="long",
    hover_data=["iata", "airport", "city", "state", "cnt"],
    size="cnt",
    color="cnt",
    zoom=3,
    title="Airport Traffic Data"
)
fig.update_layout(mapbox_style="open-street-map")

layout = html.Div(dcc.Graph(id="graph", figure=fig))

@callback(
    Output("url", "href"),
    Input("graph", "clickData"),
    prevent_initial_callback=True
)
def generate_chart(clickdata):
    if not clickdata:
        return dash.no_update
    airport_code = clickdata["points"][0]["customdata"][0]
    return f"/flight-status/{airport_code}"

pages/flight_status.py


from dash import  html, register_page

register_page( __name__, path_template="/flight-status/<airport>")

def layout(airport=None,  **other_unknown_query_strings):
    return html.H3(f"Arrivals and Departures for: {airport}")


callback-nav-fig-292

8 Likes

Cool feature! Added it in dmc-docs as well.

3 Likes