Multi-Page Apps - load query string values for components in the main layout

I’m using Multi-Page Apps with query strings. It works well for the loaded sub-layouts, but I was wondering if there is any way to get the query string values into the main (shared) part of the layout too?
E.g. here code in app.py:

from dash import Dash, html, dcc
import dash

app = Dash(__name__, use_pages=True)

def layout(number=0):
    return html.Div([
        html.Div(
            [
                html.Div(
                    dcc.Link(
                        f"{page['name']} - {page['path']}", href=page["relative_path"]
                    )
                )
                for page in dash.page_registry.values()
            ]
        ),
        html.Br(),
        html.Div(f'Number {number}'),

        dash.page_container
    ])

app.layout = layout

if __name__ == '__main__':
	app.run_server(debug=True, port=1032, use_reloader=False)

and /pages/department.py:

import dash
from dash import html

dash.register_page(__name__, name="department", path="/department")

def layout(department_id=None, **query_parameters):
    return html.Div(
		children=[
			html.Div(children=f'''
				This is department: {department_id}.
			'''),

		])

When opening the webpage with link like: http://127.0.0.1:1032/department?number=111&department_id=1
“department_id” is correctly displayed in the layout in the department.py, but I would also like to get the “number” to be displayed in the main layout part in app.py. I know I could achieve this using pattern-matched callbacks, but I hope there is a cleaner and more straightforward way.

Hello @kiteme,

You can use a dcc.Store to accomplish this. Pass the query string values to the dcc.Store and then upon update to the store, you change the elements in the app’s layout.

This would still require pattern matched callbacks though? Considering I want to have multiple pages - there is still the limitation of only one callback in all layouts being allowed to write to component (would be great if there would be a way around this!)

There is the multiplexer option, by dash-extensions for multiple callbacks to the same output.

Or, you could just have 1 callback on the app.layout which listens to the url and search as well. The location used for dash pages is, _pages_location.

@kiteme

This is a great question! I’ll add a minimal example to the dash-multi-page-app-demos github, but in the meantime, you can do this by keeping the fixed content in app.py file (ie the content that shows on every page like the header and footer), then put the rest of the content for the home page in a file in the pages folder. For example, you could call it home.py and register that page with path=“/”

dash.register_page(__name__,  path="/")

This is how it’s done in the Dash Example Index. See this link: Dash

https://dash-example-index.herokuapp.com/?code=histogram

It passes “histogram” to the search field on the home page to filter the examples for ones that include a histogram.

@AnnMarieW
I checked the example, and I understand how it loads query string values into the main page, but what I’m trying to achieve is to load query string values into both the main page (shared components, e.g. dropdowns) as well as a module sub-page. A structure like:
image
where both home.py and module1.py (assume many modules) would be able to get the data they need from the query string

@kiteme,

You should be able to do as I suggested on the main page and populate a dcc.Store by listening to the url.

@app.callback(Output(‘myData’,’data’),
Input(‘_pages_location’,’search’))
def function(search):
    return search
1 Like

@jinnyzor
I was just implementing your suggestion about having separate callback listening for query string inputs in the main page and it works great, thank you!

here new app.py for anyone looking for this solution:

from dash import Dash, html, dcc
import dash
from dash.dependencies import Input, Output

app = Dash(__name__, use_pages=True)

def layout_gen():
    return html.Div([
        html.Div(
            [
                html.Div(
                    dcc.Link(
                        f"{page['name']} - {page['path']}", href=page["relative_path"]
                    )
                )
                for page in dash.page_registry.values()
            ]
        ),
        html.Br(),
        html.Div('not loaded', id='htmldiv1'),
        dcc.Location(id='url', refresh=False),
        dash.page_container
    ])

app.layout = layout_gen

@app.callback(
    Output('htmldiv1', 'children'),
    [Input('url', 'search')]
)
def page_load(search):
    if not search:
        return []
    return f'query values: {search}'

if __name__ == '__main__':
	app.run_server(debug=True, port=1032, use_reloader=False)

department.py doesn’t need changes

1 Like