I think it depends on what you are doing. I have an app were instead of having a lot of inputs I use dcc.Link components to change the url (which in most cases would be equivalent to html.A components if you are not referring to a page outside the app), and then callbacks listening to the url to trigger different actions. I used this to avoid having to add a lot of checks of which button, dropdown, or checkbox was selected last.
@rafaelc Could you point to some example code for âcallbacks listening to the url to trigger different actionsâ?
Why do you want to use links instead of a button?
I want navigation in the app based on links rather than buttons or tabs. For example, I want to switch between different âscreensâ of the app by clicking a link in the navigation bar. See also:
I canât share the app code because itâs for work, but in general it should be something like this:
First, you need to have a dcc.Location (Iâll use an id='url' here) in your base layout, and a div where youâll include your dynamic contents (id='app-body'). Then you just use the pathname of the url component as the input to your appâs body and also the output of your dropdowns and buttons.
dash.dependencies.Output('app-body', 'children'),
[dash.dependencies.Input('url', 'pathname')])
def display_page_contents(pathname):
# Logic to extract the parameters you need from the pathname. This could vary if you are using a multi-page app, for example
args = pathname.split('/')[-1]
if args = 'ABC':
page_contents = html.Div([something ...])
elif args = 'XYZ':
page_contents = html.Div([something else...])
return page_contents
Then you could have a dropdown for example with id âmy-dropdownâ and pass the value to the url:
@app.callback(dash.dependencies.Output('url', 'pathname'),
[dash.dependencies.Input('my-dropdown', 'value')])
def change_url(value):
return value
Or a button that does the same:
@app.callback(
app.callback(dash.dependencies.Output('url', 'pathname'),
[dash.dependencies.Input('home-button', 'n_clicks')])
def button_click(n_clicks):
# When you click the button, change the end of the url to 'ABC'
return 'ABC'
Furthermore, in your app you could have dcc.Link components that change the pathname to href="/ABC" or href="/XYC", which would trigger the changes in app-body.
This works fine if the only thing I want to do with location is to switch between the screens. But what if I want to use URIs to control other aspects of the app. That is, have many different outputs that are nested within the screens have a callback using location as input. Itâs not clear to me how to make it work.
To address you question as stated, it is perfectly possible to add location as input to as many outputs as you like (nested in screens or not). However, if the whole page is updated anyway, it might be better to add location as state for the nested outputs.
Thereâs no built-in code for handling GET params, but you could parse the URI yourself and dispatch to the relevant function along with extracted arguments. Iâm hoping that weâll see a better experience around this part of Dash down the line.
Parsing the URIs is the easy part, what I am struggling with is having multiple callbacks dependent on the URI. One that switches the content of a container area, and others that control content nested within.
Could it all be handled by a single callback though?
It sounds like you want to dispatch to different callbacks based on params of the URI. Why not do all that dispatching to regular Python functions and have the complete page assembled within the one Location callback?
If Iâm misunderstanding what you mean, could you provide a more concrete example?
if you really wanted to use multiple callbcks you could have a second one listening to changes on the children prop of your container element (resulting in a cascading callback) however that will require two round trips to the server to handle.
For a similar purpose i use a setup where i parse the URL into a âpathâ, i.e. the âhttp://example.com/create_new_widgetâ part, and a list of arguments, i.e. the â?name=Widgetizerâ part. I then choose the page based on the path and pass the arguments to the page.