Allow for "null" / no output callbacks
Dash callbacks currently require at least one output. There are scenarios where one would like to act on an event from the UI, producing no output as a side-effect. Would like to be able to do:
@app.callback(None, [Input("A","value"), Input("B", "value")]
def handler(a, b):
<some application logic>
return
Right now one has to create a dummy container (such as a div) in the DOM and use it as a "fake" output sink:
...
html.Div(id='dummy1'),
...
@app.callback(Output("dummy1", "children"), [Input("A","value"), Input("B", "value")]
def handler(a, b):
<some application logic>
return None
This is all the more relevant with clientside callbacks; an example is using them as some sort of post-update hook to create clientside-only behaviour:
app.clientside_callback(
"""
function(fig) {
document.querySelector("#graph .js-plotly-plot").on("plotly_hover", event => {
...
})
return null // we can't even use dash.no_update in here
}
""",
Output('dummy', 'children'), # ideally we should not need this
Input('graph', 'figure')
)
Hi guys, I'm new here. I'd like to tackle this if possible. I've had that need myself before.
@kenshima4 you're more than welcome to give it a shot. It would be a great feature but it's not one Plotly staff currently have in our roadmap. Just be aware that it may have a number of complications - the ones that occur to me offhand are validation, determining when to trigger, MATCH pattern-matching inputs, and inclusion in the devtools callback graph - and will require quite a few tests as a result to give us confidence in the implementation. One piece of good news is that since we added allow_duplicate=True we have the machinery to support multiple no-output callbacks, as long as we implicitly set this flag in this case.
Hi @alexcjohnson I just wanted to say that I can still try and solve it but maybe at a later stage (if somebody else wants to give it a shot that's ok). My apologies but I have a few other projects that just came my way. Don't have too much time now.
It's finally possible! You can now create callbacks without providing any outputs!! Just clone this fork] and run your code without any issues.
You'll have to explicitly set a flag force_no_output=True (similar to what @alexcjohnson referred). While the flag is a temporary fix, I'm trying a general approach to make this work. Till then, give this a try.
Usage:
from dash import Dash, html, callback, Output, Input
app = Dash(__name__)
app.layout = html.Div([
html.H1(children='Title of Dash App', style={'textAlign':'center'}),
html.Div(id="result"),
html.Button(id='output-button',children="This button gives an output"),
html.Button(id='no-output-button',children="no output button"),
])
@callback(
Output("result","children"),
Input("output-button","n_clicks")
)
def make_result(n_clicks):
return f"Button with output looks like this {n_clicks}"
@callback(
Input("no-output-button","n_clicks"),
force_no_output=True
)
def make_result(n_clicks):
print("Ignored",n_clicks)
return None
if __name__ == '__main__':
app.run(debug=True)
Thank you @yashjha123 this look great, I think instead of having the force_no_output argument you can check that with length of the outputs and set the flag for the renderer. We will be happy to look at a PR if you want.
@yashjha123 do you plan on opening a pull request for this? I think it would be nice to have in the upstream.
Sorry to kept you all waiting. I just opened a PR. Can you take a review? @alexk101