1616import base64
1717import traceback
1818from urllib .parse import urlparse
19- from typing import Union
19+ from typing import Dict , Optional , Union
2020
2121import flask
2222
2929from .fingerprint import build_fingerprint , check_fingerprint
3030from .resources import Scripts , Css
3131from .dependencies import (
32- Output ,
3332 Input ,
33+ Output ,
34+ State ,
3435)
3536from .development .base_component import ComponentRegistry
3637from .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