Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multi-Page Apps - find a better way to build dash.page_registry #76

Open
AnnMarieW opened this issue Jan 12, 2022 · 3 comments
Open

Multi-Page Apps - find a better way to build dash.page_registry #76

AnnMarieW opened this issue Jan 12, 2022 · 3 comments

Comments

@AnnMarieW
Copy link
Collaborator

AnnMarieW commented Jan 12, 2022

Currently app pages are added to the dash.page_registry when dash.register_page is called. This happens as modules are loaded from the pages/ folder before the app starts. If you try to use dash.page_registry in an app in the pages/ folder, you must use it in a function, otherwise the page registry may not be complete.

Need to find a better way to build dash.page_registry so it's not necessary for people to use a function when trying to use it from within the pages/ folder.

See community discussion here

Description of the workaround here

@AnnMarieW
Copy link
Collaborator Author

Here is a potential solution as outlined by @ chriddyp
The solution will be a pull request in dash instead of here in dash-labs

Have page_registry values return a function that returns the value. So instead of:

>>> page_registry['historical']['href']
`/the-thing`

it’d be:

>>> page_registry['historical']['href']()
`/the-thing`

meaning:

>>> page_registry['historical']['href']
<function ...>
  1. Dash users would still use page_registry['historical']['href'] within their code, but the layouts would now contain functions instead of values. So pages/some_other_page.py could have:
layout = dcc.Link('Return home', 
href=page_registry['home']['href'])

where href would be a function, not the value!

  1. Then, change Dash’s serializer to handle functions. So when Dash turns Python objects into JSON strings, if it encountered a function it would simply call the function and serialize the value that it got in return

I suspect you’ll be able to do it here:
https://github.com/plotly/dash/blob/dev/dash/development/base_component.py#L206

and here:
https://github.com/plotly/dash/blob/dev/dash/development/base_component.py#L213

@AnnMarieW AnnMarieW mentioned this issue Feb 10, 2022
12 tasks
@AnnMarieW
Copy link
Collaborator Author

AnnMarieW commented Feb 12, 2022

It looks like the above solution may not be ideal:

For example, let's say you would like to create a "topics" sub-menu from within the pages/ folder.

In the proposed solution, the page["path"] is a function. This mean's that you can't create it like below by looping through dash.page_registry because page["path"] has no attribute 'startswith'

        for page in dash.page_registry.values()
        if page["path"].startswith("/topic")

But if you use the value of the function, then we are back to the same issue. The dash.page_registry is not finished building yet, so the sub-menu will not be complete.

        for page in dash.page_registry.values()
        if page["path"]().startswith("/topic")

@chriddyp do you have any other comments or suggestions?

@alexcjohnson
Copy link
Collaborator

For reference, a note I wrote in a DM with @AnnMarieW - the upshot is I don't think we need to worry about this right now but we could consider adding another mechanism in the future if it becomes a big point of friction.

The only solution I see is to move the dash.register_page calls outside the page files so you can ensure they all run first… and that kind of defeats the purpose.

I suppose there would be a way by converting the dash.register_page call into a comment, we could define the format but something like:

# register_page
# path_template="/a/<id_a>/b/<id_b>"
# id="register_page

and then we first read the file and create all the page_registry entries with that information first, then attach the modules to each entry later. But that seems like an awfully cumbersome & fragile thing to try to teach people, just so they can avoid putting some things in functions occasionally.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants