16
16
import base64
17
17
import traceback
18
18
from urllib .parse import urlparse
19
- from typing import Union
19
+ from typing import Dict , Optional , Union
20
20
21
21
import flask
22
22
29
29
from .fingerprint import build_fingerprint , check_fingerprint
30
30
from .resources import Scripts , Css
31
31
from .dependencies import (
32
- Output ,
33
32
Input ,
33
+ Output ,
34
+ State ,
34
35
)
35
36
from .development .base_component import ComponentRegistry
36
37
from .exceptions import (
@@ -346,6 +347,17 @@ class Dash:
346
347
:param hooks: Extend Dash renderer functionality by passing a dictionary of
347
348
javascript functions. To hook into the layout, use dict keys "layout_pre" and
348
349
"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
349
361
"""
350
362
351
363
_plotlyjs_url : str
@@ -383,6 +395,7 @@ def __init__( # pylint: disable=too-many-statements
383
395
background_callback_manager = None ,
384
396
add_log_handler = True ,
385
397
hooks : Union [RendererHooks , None ] = None ,
398
+ routing_callback_states : Optional [Dict [str , State ]] = None ,
386
399
** obsolete ,
387
400
):
388
401
_validate .check_obsolete (obsolete )
@@ -458,6 +471,7 @@ def __init__( # pylint: disable=too-many-statements
458
471
459
472
self .pages_folder = str (pages_folder )
460
473
self .use_pages = (pages_folder != "pages" ) if use_pages is None else use_pages
474
+ self .routing_callback_states = routing_callback_states or {}
461
475
462
476
# keep title as a class property for backwards compatibility
463
477
self .title = title
@@ -2078,18 +2092,21 @@ def router():
2078
2092
@self .callback (
2079
2093
Output (_ID_CONTENT , "children" ),
2080
2094
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
+ },
2083
2100
prevent_initial_call = True ,
2084
2101
)
2085
- def update (pathname , search ):
2102
+ def update (pathname_ , search_ , ** states ):
2086
2103
"""
2087
2104
Updates dash.page_container layout on page navigation.
2088
2105
Updates the stored page title which will trigger the clientside callback to update the app title
2089
2106
"""
2090
2107
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_ ))
2093
2110
2094
2111
# get layout
2095
2112
if page == {}:
@@ -2107,9 +2124,9 @@ def update(pathname, search):
2107
2124
2108
2125
if callable (layout ):
2109
2126
layout = (
2110
- layout (** path_variables , ** query_parameters )
2127
+ layout (** path_variables , ** query_parameters , ** states )
2111
2128
if path_variables
2112
- else layout (** query_parameters )
2129
+ else layout (** query_parameters , ** states )
2113
2130
)
2114
2131
if callable (title ):
2115
2132
title = title (** path_variables ) if path_variables else title ()
0 commit comments