Skip to content

Loading state not working correctly when layout is in a function #736

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

Closed
valentijnnieman opened this issue Mar 20, 2019 · 14 comments
Closed
Labels
bug something broken sev-2 serious problem

Comments

@valentijnnieman
Copy link
Contributor

When investigating plotly/dash-core-components#488 I noticed it does not only apply to using Location components, but rather happens when the Loading components are in a layout that comes from a function. Here's the same example code as from the issue above, but with an Input component instead of a Location component:

# -*- coding: utf-8 -*-
import dash
import dash_html_components as html
import dash_core_components as dcc
import plotly.graph_objs as go
import time
import numpy as np

from dash.dependencies import Input, Output, State

app = dash.Dash(__name__)

app.scripts.config.serve_locally = True
app.config['suppress_callback_exceptions']=True
app.layout = html.Div([
    dcc.Input(id='url'),
    dcc.Loading([html.Div(id='page-body')])
])

def make_layout(pathname):

    return html.Div([
    html.Div([
            dcc.Loading(
            id="loading-1",
            children=[html.Div(id='figure-container')],
            type="circle"),
            html.Button(id="input-1", children='Input triggers nested spinner')
        ], style={'width': 400}),
    html.Div([
            dcc.Loading(
            id="loading-2",
            children=[html.Div([dcc.Graph(id='figure-2')])],
            type="circle"),
            html.Button(id="input-2", children='Input triggers nested spinner')
        ], style={'width': 400})
    ])

@app.callback(Output('page-body', 'children'),
              [Input('url', 'value')])
def page(pathname):

    return make_layout(pathname)

@app.callback(Output("figure-container", "children"), [Input("input-1", "n_clicks")])
def input_triggers_nested(n_clicks):
    time.sleep(2)
    fig = go.Scatter(
        x=np.random.random(size=10),
        y=np.random.random(size=10)
    )

    return dcc.Graph(figure=dict(data=[fig]), id='figure-1')


@app.callback(Output("figure-2", "figure"), [Input("input-2", "n_clicks")])
def input_triggers_nested(n_clicks):
    time.sleep(2)
    fig = go.Scatter(
        x=np.random.random(size=10),
        y=np.random.random(size=10)
    )
    return dict(data=[fig])

if __name__ == "__main__":
    app.run_server(debug=True, port=8053)

Because the Loading components are being appended to page-body via the make_layout function, the spinners aren't showing upon initial loading. I suspect this is because we're not setting the loading_state property correctly on nested components, or, the requestQueue does not handle nested component updates properly.

@alexcjohnson alexcjohnson transferred this issue from plotly/dash-renderer May 22, 2019
@cannatag
Copy link

cannatag commented Dec 7, 2019

I have the same problem on a multipage app. Any news on this?

@bennyweise
Copy link

I've also just discovered this problem on my multipage app, so would be interested in any updates as well.

@CP-Vub
Copy link

CP-Vub commented Dec 14, 2019

I as well am having similar erratic loading animation behavior with my multipage app, so just like the people above me, I would be interested in an update regarding this issue.

@locha0519
Copy link

locha0519 commented Dec 23, 2019

I had the same problem following the tutorial but I found two workarounds to solve it.

One is using dcc.Interval to refresh the page after loading it, and limiting the number of updates by max_intervals. However, this method is inefficient since it will unnecessarily refresh the page several times.

The better solution I found is to combine dash apps with WSGI Apps. I modified the tutorial and tested the method on my app, witch is formed by an image gallery (index page) and zoom-in images (zoom-in pages). The method works well and is faster than the previous workaround. Here is a simplified test code, you can have a try:

import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
from flask import Flask, redirect
from werkzeug.serving import run_simple
from werkzeug.wsgi import DispatcherMiddleware

# Host wsgi app
flask_app = Flask(__name__)

@flask_app.route('/')
def index():
    # redirect to image gallery dash app
    return redirect('/index')

# Image gallery dash app
app_index = dash.Dash(
    'app_index',
    requests_pathname_prefix='/index/'
)
app_index.layout = html.Div([
    html.H1('Image gallery'),
    html.Div([
        html.A(
            html.Img(src='http://www.kanahei.com/upload/2019/12/12_wpsam.jpg'),
            href='/zoomin/image1'),
        html.A(
            html.Img(src='http://www.kanahei.com/upload/2019/11/11_wpsam.jpg'),
            href='/zoomin/image2'),
    ])
])

# Zoomin images dash app
app_zoomin = dash.Dash(
    'app_zoomin',
    requests_pathname_prefix='/zoomin/'
)
app_zoomin.layout = html.Div([
    dcc.Location(id='url'),
    html.H1('Zoomin image'),
    html.Div([
        html.Div(id='pathname'),
        html.Img(id='zoomin_image',
                 style={'max-width': '600px',
                        'max-height': '600px'}),
    ]),
    html.Div([
        html.A('Go back to gallery', href='/'),
    ])
])

@app_zoomin.callback(
    [Output('zoomin_image', 'src'),
     Output('pathname', 'children')],
    [Input('url', 'pathname')])
def update_zoomin_images(pathname):
    if pathname == '/zoomin/image1':
        return 'http://www.kanahei.com/upload/2019/12/01_16x9.jpg', pathname
    elif pathname == '/zoomin/image2':
        return 'http://www.kanahei.com/upload/2019/11/01_16x9.jpg', pathname
    return None, pathname

# Combine apps
application = DispatcherMiddleware(flask_app, {
    '/index': app_index.server,
    '/zoomin': app_zoomin.server,
})

# Run server
if __name__ == '__main__':
    run_simple('0.0.0.0', 8050, application)

@MM-Lehmann
Copy link

I can confirm this issue.
Is there any plan in place to get this resolved?

@orangeluc
Copy link

Have the same issue, is there any update on this? Thx!

@mschrader15
Copy link

I have the same issue as well

@aoelvp94
Copy link

Same here. Any update?

@JamesMckenzie4
Copy link

Was there any solution to this problem? Cheers.

@chaseedge
Copy link

Just keeping this alive, I'm having the same problem.

@tuchandra
Copy link

tuchandra commented Dec 5, 2022

I'm running into this too. I confirmed with vanilla dash, but first encountered this when using the excellent dash-mantine-components. The library demos a button that shows a loading spinner & greys itself out while being clicked (link), but it unfortunately does not work if the button is defined in a function.

Defining components within functions is absolutely essential for anything more than the simplest of apps. The code gets too out of hand with everything defined at the module level; it's disappointing that this doesn't work. I don't know where to begin debugging this or if help is even wanted, but I'd be willing to try digging in myself with a little guidance.

@idling-mind
Copy link

Having the same issue. Is there any workaround for this?

@Coding-with-Adam Coding-with-Adam added bug something broken sev-2 serious problem P2 considered for next cycle labels Dec 21, 2023
@Coding-with-Adam Coding-with-Adam removed the P2 considered for next cycle label Jan 18, 2024
@AnnMarieW
Copy link
Collaborator

I know this is an old issue, but there seems to be recent activity. I ran the original example and everything looks fine to me. Can anyone provide a recent example that replicates this issue? Just asking because I'm working on a dcc.Loading PR right now.

dcc_loading_736

@Coding-with-Adam
Copy link
Contributor

closed by #2760

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug something broken sev-2 serious problem
Projects
None yet
Development

No branches or pull requests