App callback without an output

I would like to bump up the topic of callbacks without outputs again because I discovered this to be a common use-case if you use Dash to communicate with other processes.

One example that comes directly into my mind is if you communicate with a Redis server and want to write some values depending on the user input in the Dash app. In a current case I need to control a process that captures the data. The parameters for the capturing like sample time, buffer size and measurement can be controlled by the user via Dash client. So I find myself creating dummy divs for each parameter for being able to transfer them to the Redis server. I know this is the recommended workaround however I think it is not a nice solution and creates unnecessary complexity in the frontend.

I would very much prefer a solution like this:

@app.callback(Output(None), [Input("samplerate_slider", "value"])
def update_samplerate(value: int) -> None:
    redis_client.set("samplerate", value)

Another use-cases I can think of that currently needs dummy divs and could be simplified by this approach:

So maybe we can revive the discussion about callbacks without outputs again :slight_smile: I’m also very willing to offer my help when it comes to implementation.

@trav Thanks for the link but I can not see how this addresses the issue at hand :confused:

Necessity of creating a dummy div seems weird. What if I want to do something on timer and don’t need to return anything immediately?

Typically, you would poll updates using an interval component.

You still need an Output e.g. a dummy div for this to work which is not a nice solution if you want to pass information to the Backend (e.g. Redis server).

Yes, but you can just return a blank string. It’s not super elegant, but I don’t see that it does much harm.

I agree on that. It is also cumbersome if you have multiple controls that only do backend operations. You need to create a separate dummy Div for each of these controls. My point is that it would be more convenient to create callbacks without beeing forced to add Outputs.

I made a wrapper for that purpose,

But it just does the same thing under the hood.

Nice work. I didn’t know about your extension and I will definetely give it a try :+1: I would still like to know why Outputs are enforced by Dash. Is it some limitation of React?

Thanks! No, it is a ‘limitation’ (though I would rather call it a design choice) of Dash itself.

Yes it looks this way. I would like to understand the reason for it though. It does not make much sense to force such workarounds from my point of view.

Well, a key design point of dash is keeping the server stateless. With that ind mind, what you are doing is practically a hack, and I can thus understand why the plotly team didn’t make any efforts to make it pretty.

I get your point. I use Dash to write GUIs for test stations and machines. So it is mandatory for me that it can handle states. I keep asking myself if Dash is the right choice for this kind of task.

I have previously used Dash for this kind of application, and i found it to be a good compromise between flexibility and ease of use. The reason Dash was designed with a stateless server in mind is to enable scaling to many (thousands) of users. You don’t really need that (I assume?), so it that sense it doesn’t matter that you violate this design principle.

Thanks, that’s reassuring :slight_smile: So far I didn’t get in trouble with my hacks, either. And yes the use-case is only 1 or a few users at a time.

This is an old post, but it’s still popular, so I wanted to make sure anyone who finds it through a search gets the current answer.

Callbacks with no outputs have been supported since Dash 2.17:

Callbacks with No Outputs

New in 2.17

All previous examples have inputs that trigger callbacks as well as outputs that are updated. Callbacks also support having no outputs. This can be useful for cases where you want some code to run when an action triggers a callback, but you don’t want to update any component property. For example, you may want to fetch some data and save it, send emails, or interact with other external services outside of the Dash ecosystem.

In the following example, using the dcc.Upload component, we allow the user to upload a file to the server.

Our example has no return statements. Callbacks without outputs should not return a value, because there are no outputs to update. If you return a value from the callback when there is no output to update, you’ll see an error in Dash Dev Tools.

import base64

from dash import Dash, html, Input, Output, dcc, callback, State


app = Dash(__name__)

app.layout = html.Div(
    [
        html.H1("No Output Example"),
        dcc.Upload(
            id='upload-data-to-server',
            children=html.Div([
                'Drag and Drop or ',
                html.A('Select Files')
            ]),
            style={
                'width': '100%',
                'height': '60px',
                'lineHeight': '60px',
                'borderWidth': '1px',
                'borderStyle': 'dashed',
                'borderRadius': '5px',
                'textAlign': 'center',
                'margin': '10px'
            },
        ),
    ]
)


@callback(
    Input("upload-data-to-server", "contents"),
    State('upload-data-to-server', 'filename'),
    # We could also use `running` on the callback to disable the button
    # while the callback is running:
    # running=[(Output("upload-data-to-server", "disabled"), True, False)]
)
def update_output_div(contents, filename):
    if contents is not None:
        _, content_string = contents.split(',')
        decoded = base64.b64decode(content_string)
        directory = './uploaded_files'
        with open(f'{directory}/{filename}', 'wb') as f:
            f.write(decoded)


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