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

[BUG] No callback to dcc.Location when two or more dcc.Location are placed in layout #1312

Closed
papalagichen opened this issue Jun 25, 2020 · 3 comments · Fixed by #2555
Closed

Comments

@papalagichen
Copy link

Thank you so much for helping improve the quality of Dash!

We do our best to catch bugs during the release process, but we rely on your help to find the ones that slip through.

Describe your context
Please provide us your environment so we can easily reproduce the issue.

  • replace the result of pip list | grep dash below
dash                      1.13.3
dash-auth                 1.3.2
dash-bootstrap-components 0.10.2
dash-core-components      1.10.1
dash-html-components      1.0.3
dash-renderer             1.5.0
dash-table                4.8.1
  • if frontend related, tell us your Browser, Version and OS

    • OS: [e.g. macOS]
    • Browser [e.g. chrome, safari, firefox]
    • Version [e.g. 83.0.4103.116, 13.1.1, 77.0.1]

Describe the bug

In a multi-page app, browser's back and forward buttons do not work when multiple dcc.Location components are placed in layout. No callback is triggered nor request is sent when browser's back or forward button is clicked. As a result, I see the URL is changed while the page is not rendered accordingly.

Two dcc.Location are placed in the layout like following code snippet.

url_bar_and_content_div = html.Div([
    dcc.Location(id='url', refresh=False),
    dcc.Location(id='url2', refresh=False),
    html.Div(id='page-content')
])

Expected behavior

When URL is changed, the corresponding callback should be called and page should be rendered accordingly.

Screenshots

@wmachadoa
Copy link

@papalagichen Did you find a solution to this? I'm experiencing the same issue

@AnnMarieW
Copy link
Collaborator

Here is a minimal example.

Note that this is only reproducible when not using Pages

  • With one dcc.Location, the callback updates the page content and the browser forward and back buttons work.
  • With two dcc.Location when you click on the links everything works fine, but the browser forward and back button update the URL, but the page does not update unless you hit the browser refresh button
from dash import Dash, dcc, html, Input, Output, callback


page1 = html.Div("PAGE 1 CONTENT")
page2 = html.Div("Page 2 content")

app = Dash(__name__, suppress_callback_exceptions=True)
server = app.server

app.layout = html.Div([
    dcc.Location(id='url', refresh=False),
    #dcc.Location(id='url2', refresh=False),

    dcc.Link('Go to Page 2', href='/page2'),
    html.Br(),
    dcc.Link('Go to Page 1', href='/page1'),
    html.Div(id='page-content')
])


@callback(Output('page-content', 'children'),
              Input('url', 'pathname'))
def display_page(pathname):
    if pathname == '/page1':
        return page1
    elif pathname == '/page2':
        return page2
    elif pathname == '/':
        return page1
    else:
        return '404'

if __name__ == '__main__':
    app.run_server(debug=True)

Here is a similar app with Pages - Can't reproduce the error:

import dash
from dash import Dash, html, dcc

app = Dash(__name__, use_pages=True, pages_folder="")


dash.register_page("stocks", layout=html.Div("stocks page"))
dash.register_page("home", path="/", layout=html.Div("home page"))

app.layout = html.Div(
    [
        dcc.Location(id="url", refresh=False),
        dcc.Location(id="url2", refresh=False),

        dcc.Link('Stocks', href='/stocks'),
        html.Br(),
        dcc.Link('Home', href='/'),
        dash.page_container,
    ]
)

if __name__ == "__main__":
    app.run(debug=True)

jowlo added a commit to jowlo/dash that referenced this issue Jun 1, 2023
Multiple dcc.Location were replacing the others event handlers for
'popstate'. If any dcc.Location was unmounted, there was no event
handler left

fix plotly#1312
jowlo added a commit to jowlo/dash that referenced this issue Jun 2, 2023
Multiple dcc.Location were replacing the others event handlers for
'popstate'. If any dcc.Location was unmounted, there was no event
handler left

fix plotly#1312
@jowlo
Copy link
Contributor

jowlo commented Jun 2, 2023

I encountered the same problem while using pages. The bug is triggered when one of the dcc.Locations is removed from the layout, which unregisters the window.onpopstate event handler that triggers the callback.

Having a Location in one of the pages is enough to trigger it, which will also break the browser's back button for the pages. Adapting the example by @AnnMarieW above:

import dash
from dash import Dash, html, dcc

app = Dash(__name__, use_pages=True, pages_folder="")


dash.register_page("stocks", layout=[
    html.Div("stocks page"),
    dcc.Location(id="url", refresh=False),
])
dash.register_page("home", path="/", layout=html.Div("home page"))

app.layout = html.Div(
    [
        dcc.Location(id="url2", refresh=False),

        dcc.Link('Stocks', href='/stocks'),
        html.Br(),
        dcc.Link('Home', href='/'),
        dash.page_container,
    ]
)

if __name__ == "__main__":
    app.run(debug=True)

I have made PR in #2555 that should fix the issue.

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

Successfully merging a pull request may close this issue.

4 participants