Skip to content

Commit 5b41207

Browse files
committed
Routing callback states
1 parent 6eaf2e1 commit 5b41207

File tree

1 file changed

+26
-9
lines changed

1 file changed

+26
-9
lines changed

dash/dash.py

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
import base64
1717
import traceback
1818
from urllib.parse import urlparse
19-
from typing import Union
19+
from typing import Dict, Optional, Union
2020

2121
import flask
2222

@@ -29,8 +29,9 @@
2929
from .fingerprint import build_fingerprint, check_fingerprint
3030
from .resources import Scripts, Css
3131
from .dependencies import (
32-
Output,
3332
Input,
33+
Output,
34+
State,
3435
)
3536
from .development.base_component import ComponentRegistry
3637
from .exceptions import (
@@ -346,6 +347,17 @@ class Dash:
346347
:param hooks: Extend Dash renderer functionality by passing a dictionary of
347348
javascript functions. To hook into the layout, use dict keys "layout_pre" and
348349
"layout_post". To hook into the callbacks, use keys "request_pre" and "request_post"
350+
351+
:param routing_callback_states: When using Dash pages (use_pages=True), allows to
352+
add new States to the routing callback, to pass additional data to the layout
353+
functions. The syntax for this parameter is a dict of State objects:
354+
`routing_callback_states={"language": State("language", "value")}`
355+
This allows things like (non-exhaustive list):
356+
* A language dropdown that will be passed to every layout function,
357+
for internationalisation
358+
* Serialising the state in URL hashes without reloading the page on every
359+
input update, and using the hash on first load / refresh
360+
* Passing a global app data store on page load
349361
"""
350362

351363
_plotlyjs_url: str
@@ -383,6 +395,7 @@ def __init__( # pylint: disable=too-many-statements
383395
background_callback_manager=None,
384396
add_log_handler=True,
385397
hooks: Union[RendererHooks, None] = None,
398+
routing_callback_states: Optional[Dict[str, State]] = None,
386399
**obsolete,
387400
):
388401
_validate.check_obsolete(obsolete)
@@ -458,6 +471,7 @@ def __init__( # pylint: disable=too-many-statements
458471

459472
self.pages_folder = str(pages_folder)
460473
self.use_pages = (pages_folder != "pages") if use_pages is None else use_pages
474+
self.routing_callback_states = routing_callback_states or {}
461475

462476
# keep title as a class property for backwards compatibility
463477
self.title = title
@@ -2078,18 +2092,21 @@ def router():
20782092
@self.callback(
20792093
Output(_ID_CONTENT, "children"),
20802094
Output(_ID_STORE, "data"),
2081-
Input(_ID_LOCATION, "pathname"),
2082-
Input(_ID_LOCATION, "search"),
2095+
inputs={
2096+
"pathname_": Input(_ID_LOCATION, "pathname"),
2097+
"search_": Input(_ID_LOCATION, "search"),
2098+
**self.routing_callback_states,
2099+
},
20832100
prevent_initial_call=True,
20842101
)
2085-
def update(pathname, search):
2102+
def update(pathname_, search_, **states):
20862103
"""
20872104
Updates dash.page_container layout on page navigation.
20882105
Updates the stored page title which will trigger the clientside callback to update the app title
20892106
"""
20902107

2091-
query_parameters = _parse_query_string(search)
2092-
page, path_variables = _path_to_page(self.strip_relative_path(pathname))
2108+
query_parameters = _parse_query_string(search_)
2109+
page, path_variables = _path_to_page(self.strip_relative_path(pathname_))
20932110

20942111
# get layout
20952112
if page == {}:
@@ -2107,9 +2124,9 @@ def update(pathname, search):
21072124

21082125
if callable(layout):
21092126
layout = (
2110-
layout(**path_variables, **query_parameters)
2127+
layout(**path_variables, **query_parameters, **states)
21112128
if path_variables
2112-
else layout(**query_parameters)
2129+
else layout(**query_parameters, **states)
21132130
)
21142131
if callable(title):
21152132
title = title(**path_variables) if path_variables else title()

0 commit comments

Comments
 (0)