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

fix multiple concurrent loading states #1310

Merged
merged 4 commits into from
Jun 25, 2020
Merged

fix multiple concurrent loading states #1310

merged 4 commits into from
Jun 25, 2020

Conversation

alexcjohnson
Copy link
Collaborator

@alexcjohnson alexcjohnson commented Jun 24, 2020

Fixes https://github.com/plotly/dash-core/issues/195
Regression from #1254 - only one loading state could be shown at a time.

  • I have run the tests locally and they passed. (refer to testing section in contributing)

  • I have added tests, or extended existing tests, to cover any new features or bugs fixed in this PR

  • I have added entry in the CHANGELOG.md

forEach(p => {
target = (target[p] =
target[p] ??
p === 'children' ? [] : {}
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Turns out ?? has higher precedence than ? in JS 🙈 The only necessary part of this fix is the extra parentheses around this line.

Added the typeof path[i + 1] clause so that the [] vs {} distinction is correct - though it doesn't seem to actually cause problems when the container has the wrong type 🤷

@chriddyp
Copy link
Member

Do we want to test loading states for chained callbacks too? Dropdown A ➡️ Dropdown B ➡️ Graph. If Dropdown A changes, do we show a loading state for Graph before Dropdown B is updated?

I'm not sure what the existing behavior is but seems like it could be another piece of logic that could've changed during the refactor.

@alexcjohnson
Copy link
Collaborator Author

Do we want to test loading states for chained callbacks too?

Sure, I can add a test for that later tonight.

@chriddyp
Copy link
Member

Here is a test case for chained callbacks & loading states:

import dash
from dash.dependencies import Input, Output
import dash_core_components as dcc
import dash_html_components as html
import time

app = dash.Dash(__name__)

app.layout = html.Div([
    html.Button(id='button', children='Start', n_clicks=0),

    html.Div(
        dcc.Loading(html.Div(id='output-1', style={
            'width': 200,
            'height': 200,
            'backgroundColor': 'hotpink',
        })),
        style={'display': 'inline-block'}
    ),

    html.Div(
        dcc.Loading(html.Div(id='output-2', style={
            'width': 200,
            'height': 200,
            'backgroundColor': 'rebeccapurple',
        })),
        style={'display': 'inline-block'}
    ),

    html.Div(
        dcc.Loading(html.Div(id='output-3', style={
            'width': 200,
            'height': 200,
            'backgroundColor': 'green',
        })),    
        style={'display': 'inline-block'}
    ),

    html.Div(
        dcc.Loading(html.Div(id='output-4', style={
            'width': 200,
            'height': 200,
            'backgroundColor': '#FF851B',  # orange
        })),
        style={'display': 'inline-block'}
    )
])

@app.callback(Output('output-1', 'children'), [Input('button', 'n_clicks')])
def update_output_2(n_clicks):
    time.sleep(2)
    return 'Output 1: {}'.format(n_clicks)


@app.callback(Output('output-2', 'children'), [Input('output-1', 'children')])
def update_output_2(children):
    time.sleep(2)
    return 'Output 2: {}'.format(children)


@app.callback([Output('output-3', 'children'), Output('output-4', 'children')], [Input('output-2', 'children')])
def update_output_2(children):
    time.sleep(2)
    return [
        'Output 3: {}'.format(children),
        'Output 4: {}'.format(children)
    ]



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

In 1.12.0 we don't display a loading state for grandchildren, only immediate children. Looks like the 1.13 behavior is the same right now.

Here's what this looks like in 1.12.0

1 12

@alexcjohnson
Copy link
Collaborator Author

Thanks @chriddyp - added that app as a test case in a225922

Copy link
Member

@chriddyp chriddyp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💃 beautiful

@alexcjohnson alexcjohnson merged commit 0d528ac into dev Jun 25, 2020
@alexcjohnson alexcjohnson deleted the multi-loading branch June 25, 2020 13:02
rpkyle added a commit to plotly/dashR that referenced this pull request Jun 25, 2020
This release upgrades dash-renderer from v1.4.1 to v1.5.1, and is timed with the release of Dash for Python v1.13.4. This update also addresses a regression that prevented multiple loading states from displaying concurrently when a callback updates multiple outputs, as noted in [plotly/dash#1310](plotly/dash#1310).
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 this pull request may close these issues.

2 participants