Pass data from one callback to another without passing to any outputs

I am trying to find ways to exchange data between two callbacks without involving input or output, if possible. Here’s some code for illustration purposes.

# Callback #1
@app.callback(Output('y','value'), 
                           Input('x','value')
                          )
def example1(x):

       # make a api or function call 
       val = make_api_call(x) 

       return no_update 



# Callback #2
@app.callback(Output('y','value'), 
                           Input('x','value')
                          )
def example2(x):

       # read val

       return no_update

I’d like to pass val from the above callback1 to callback2. val isn’t not assigned to any of the fields in app.layout. It is just a variable in the function. Is there a way to accomplish this? or do I have to use hacky ways to assign val to a hidden div and then pass that onto the callback and dcc.Store?

Hi,

I believe the easiest way to share data between callbacks is to use dcc.Store. You would have to update it with the first callback by passing val to dcc.Store and then using it as Input or State on your second callback.

The other thing that you can consider is if you need two callbacks in the first place. It is difficult to judge without knowing the actual use case.

Hope this helps!

I see. Can you share an example of passing a variable to dcc.Store that is not assigned to any element in the layout?

Here’s a borderline trivial example:

from dash import Dash, html, dcc, Output, Input, State
from dash.exceptions import PreventUpdate

app = Dash(__name__)

app.layout = html.Div(
    [
        dcc.Input(id="input"),
        dcc.Store(id="store"),
        html.P(id="output")
    ]
)

@app.callback(
    Output("store", "data"),
    Input("input", "value"),
)
def update_store(value):
    if not value:
        raise PreventUpdate
    return {
        "value": value,
        "style": {
            "color": "red" if len(value) % 2 == 0 else "blue"
        }
    }

@app.callback(
    Output("output", "children"),
    Output("output", "style"),
    Input("store", "data")
)
def update_style(data):
    if not data:
        raise PreventUpdate
    return data["value"], data["style"]

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

As I mentioned before, there is a trade-off in using a pattern like this vs. a single callback.

1 Like

Thx.

In my case, the val is return from an API / Function call. Can I pass a val to another callback or dcc.Store if it is not assigned to a component in the layout? In your code, you’re passing input from the layout.

Specifically, this line my example:

val = make_api_call(x)

val is not assigned to a component in the layout, I just need to pass it to another callback.

Sorry, if it wasn’t clear in the question.

val in your example depends on x, which is one of the callback arguments, right?

In this specific case, I don’t see why you would need a second callback where you provide val, given that it is updated by x. The only reason to do it is if you want to use val in multiple components…

Maybe I am missing the point of why you need to do this, so apologies for not being clear.

right, val depends on x, but val is not returned by the callback function to any of the components in the layout.

There are a couple of reasons:

a) I have a multi-tab / page app, and I need to access the val across tabs / pages, without having to make duplicates calls.
b) Cleaner / interpretable code. I can combine the callbacks, however, there is a lot going on in the callbacks and would ideally like to keep it separate.

I guess, what I am looking for is a way to exchange data between callbacks without it being returned back to a component in the layout.

Ok, so as in my first suggestion, just use a Store component to update val. You van pass anything that is json serializable to it, so very nice for api responses in this format.

1 Like

@jlfsjunior

ok, so, I am doing doing this. In my app layout, I have a dcc.Store component.

The first callback, stores the result. And when I print the data property of the dcc.Store element in second callback it is empty. Code for Illustration.

from dash import Dash, html, dcc, Output, Input, State
from dash.exceptions import PreventUpdate

app = Dash(__name__)

app.layout = html.Div(
    [
        dcc.Input(id="input"),
        dcc.Store(id="store", storage_type="local")
    ]
)

# callback #1
@app.callback(
    Output("store", "data"),
    Input("input", "value"),
)
def update_store(value):
    if not value:
        raise PreventUpdate
    return {
        "value": value,
    }

# callback #2
@app.callback(
    Output("output", "children"),
    State("store", "data")
)
def update(data):

       print(data)   <-- This is empty. 

       if not data:
           raise PreventUpdate
       return data["value"]

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

value here is of type dict and thus JSON serializable. I am trying to figure out why data is empty. I do not run into any errors when storing to dcc.Store component in callback #1.

Switching from State to Input fixed the issue. Not sure why though :joy:

Glad you solved! The reason it was empty is because value is initially None in the first callback, so the update is prevented… Then in the second callback you didn’t have anyInput variable to trigger it, therefore it does not update.

1 Like