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

Callback context #608

Merged
merged 8 commits into from
Feb 21, 2019
Merged

Callback context #608

merged 8 commits into from
Feb 21, 2019

Conversation

T4rk1n
Copy link
Contributor

@T4rk1n T4rk1n commented Feb 14, 2019

See example in the FAQ section under "How do I determine which Input has changed?": https://dash.plot.ly/faqs

original PR below


Add a callback context object for the dash package.

  • dash.callback_context.inputs/states a dict with the id and prop as key for the inputs/states value of a callback.
  • dash.callback_context.triggered which inputs has fired (called setProps)

These properties are only available inside a callback.

Basic example:

import dash
import dash_html_components as html

from dash.dependencies import Output, Input
from dash.exceptions import PreventUpdate

app = dash.Dash(__name__)

BUTTONS = ['btn-{}'.format(x) for x in range(1, 6)]

app.layout = html.Div([
    html.Div([
        html.Button(x, id=x) for x in BUTTONS
    ]),
    html.Div(id='output'),
])


@app.callback(Output('output', 'children'),
              [Input(x, 'n_clicks') for x in BUTTONS])
def on_click(*args):
    if not dash.callback_context.triggered:
        raise PreventUpdate
    trigger = dash.callback.triggered[0]
    input_value = dash.callback_context.inputs.get(trigger)
    return 'Just clicked {} for the {} time!'.format(
        trigger.split('.')[0], input_value)


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

Closes #291, Closes #59

@alexcjohnson
Copy link
Collaborator

@T4rk1n great solution, and very nice architecture - I didn't know about flask.g but that certainly seems the ideal place to attach this kind of thing. And seems like this will extend nicely to handle things like previous state.

Only question is about the name - I feel like dash.callback is apt to get confused with app.callback - can we call it request or context?

@T4rk1n
Copy link
Contributor Author

T4rk1n commented Feb 14, 2019

Yes, flask.g is alive for the duration of the request only, so each callback get it's own "scope" managed.

Only question is about the name - I feel like dash.callback is apt to get confused with app.callback - can we call it request or context?

That was also one of my concern, but I dismissed request because our users knows they are in a callback but maybe not a request, so it more specific and not to be confused with flask.request which handle much more. context just feel too generic.

@T4rk1n
Copy link
Contributor Author

T4rk1n commented Feb 14, 2019

  • triggered only contains triggered inputs (now all props by setProps)

@alexcjohnson
Copy link
Collaborator

I dismissed request because our users knows they are in a callback but maybe not a request, so it more specific and not to be confused with flask.request which handle much more. context just feel too generic.

Fair points. I'm still not excited about callback though... in addition to the potential confusion, it implies that this is the callback, whereas it's really just extra info being provided to the callback, detailing how it was invoked. Perhaps callback_info or callback_data then? Or even callback_context, as you use internally. The way you set it up, this object is persistent, so users can import it up front with an alias from dash import callback_context as ctx or something - so I'm not super worried about a long name.

Copy link
Collaborator

@alexcjohnson alexcjohnson left a comment

Choose a reason for hiding this comment

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

Fantastic! 💃 once dash-renderer is released with the changes so we can reference it in setup.py (and put back regular references in dev-requirements)

If you feel like making an RC for this you can, but I don't think it's necessary to do so just to get feedback. Once there is a release for it though we should let community.plot.ly know, and make an issue in dash-docs about it.

@T4rk1n
Copy link
Contributor Author

T4rk1n commented Feb 14, 2019

From discussion with @Bachibouzouk , the triggered inputs should also contains the value for a cleaner api.

triggered = [{'id': 'input.value', 'value': 'foo'}]

@T4rk1n T4rk1n mentioned this pull request Feb 15, 2019
3 tasks
@matthijsramlab
Copy link

matthijsramlab commented Feb 20, 2019

This is awesome, when will it be released?

@T4rk1n T4rk1n merged commit 1249ffb into master Feb 21, 2019
@T4rk1n T4rk1n deleted the callback-context branch February 21, 2019 16:22
@T4rk1n
Copy link
Contributor Author

T4rk1n commented Feb 21, 2019

@matthijsramlab Just merged, going into next release.

HammadTheOne pushed a commit that referenced this pull request Jul 23, 2021
fix infinite loop
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.

3 participants