I’m in the process of building a Multi-Page app with Dash and I’m having some trouble updating the URL correctly.
I’ve got all the basics set up thanks to the page on URLs in the documentation, however I’ve run into a problem. One of my pages is generating it’s content based on the value of a dropdown and I would like to store that value as part of the URL to allow direct navigation to that page. Setting the dropdown based on the URL isn’t a big deal as I can just parse the url, but I already have navigation buttons between pages. As such I cannot set another callback output to update the URL as they collide. Is there a way that I can have both the button callback and the dropdown callback both call into a function so that the URL is only updated in one place?
Thanks for writing in. You’re absolutely right about the problem: the app structure you proposed includes an infinite loop between the dropdown and the url.
There’s no issue with using dropdowns for navigation, and using them to toggle between different URL names however: you can use a dropdown to change the URL, then the URL to populate new page content.
The general format of multi-page apps involve a
"header" (perhaps just the URL, in your case a dropdown that serves as navigation) and then a major
"page-content" div. With this in mind, it is possible to retrieve information from generated page-content and store it in the header (the easiest way is using hidden divs as explained here: https://dash.plot.ly/sharing-data-between-callbacks)
You’ll still have to be careful for circular logic, but otherwise you should be able to achieve what you’re looking to do.
Thanks for the suggestion. But I am still confused. The original question is about two input components (a dropdown and a button) change one output component (URL). And your suggestion is to follow the doc https://dash.plot.ly/sharing-data-between-callbacks which uses a hidden Div to update the URL.
If I understand correctly, the problem is not changed. The problem is still multiple input components are going to update one output components. No matter the one output component is a Location (URL) component or a hidden Div component.
I try to solve this problem with multiple inputs callback. However, current version of Dash requires all input components are rendered on the page to trigger the callback. On the other hand, current version of Dash does not allow the same output component to be registered more than once. As a result, if any input component is not rendered on the page at the beginning, it is not possible to change the url by the callback.
I tried another workaround for this, to use multiple Location components. So that each input component can bind to its own location component. However, this solution is not clean at all.
Can you give us an example to explain more? Thanks!
I found a workaround.
Use two dcc.Location components. One serves as input, another serves as output. They will sync their value by themselves automatically. Since the input and output components have different names, the callback validation will pass.
@app.callback(Output('url-output', 'pathname'), Input('component-a', 'value'))
@app.callback(Output('component-a', 'value'), Input('url-input', 'pathname'))