🚀 Gen 5 of the leading AI app deployment platform launches October 6. Click for the livestream.

Binding a callback inside another callback

We are trying to bind a callback to a component during the execution of another callback. However, when the first callback is called it doesn’t set the second callback for some reason.

So, here it is a simple code example:

import dash
import dash_html_components as html
from dash.dependencies import Input, Output, State

app = dash.Dash('test')

app.layout = html.Div([
      html.Div([
         html.Div([
            html.Button(
               'Bind callbacks',
               id='bt1',
            ),
            html.P(id='result1')
         ]),
         html.Div([
            html.Button(
               'Button to be bound',
               id='bt2',
            ),
            html.P(id='result2')
         ])
      ],
      style={'display': 'flex'}
      )
 ])

@app.callback(
   Output('result1', 'children'),
   [Input('bt1', 'n_clicks')]
)
def press_bt1(click):
   if click and click % 2 == 1:
      bind_callbacks2(app)
      return 'Pressed bt1'

   return None


def bind_callbacks2(app):

   @app.callback(
      Output('result2', 'children'),
      [Input('bt2', 'n_clicks')]
   )
   def press_bt2(click):
      if click and click % 2 == 1:
         print('BT2 click')
         return 'Pressed bt2'

      return None

app.run_server(debug=True, port=8085)

We have two buttons: bt1 and bt2. We expected that when we click bt1 a new callback, not previously set, would be bound to bt2 from there on. However, although the callback press_bt1 is indeed called and run, it does not set the press_bt2 callback to bt2.

Curiously, if you launch the app, go to http://127.0.0.1:8085/, press bt1, reload the page and press bt2; you’ll see that the second callback press_bt2 has been successfully bound to bt2.

You might be wondering why we want to do this instead of simply binding the callbacks beforehand and using app.config['suppress_callback_exceptions'] = True. The problem here is that we actually want to do something more complicated: We want to generate new components from another callback (different component depending on different selection chosen by the user) and bind their corresponding bindings too, all in runtime.

You can see a full example of what I mean by this in this repo: https://github.com/Akronix/Dash-test-nesting-callbacks-in-runtime
In that repo you can see that a different button is generated and added to the layout depending on the the RadioItem selection; that works fine, but again the callback for that button is never bound. Also, if you select the first option, then reload the app and select again that first option, you will get a dash.exceptions.CantHaveMultipleOutputs exception, since the previous binding and the new one are redundantly being attached to the same button (we could control that it’s bound only once, but the problem here is that it isn’t bound in the first click to the RadioItem).

It’s not possible to define callbacks inside callbacks - they all need to be defined upfront. See Dynamic Controls and Dynamic Output Components

1 Like

hum, and is there any plans to change this or to workaround this?

Thanks!

At the risk of sounding condescending, this might be a case of https://en.m.wikipedia.org/wiki/XY_problem.

Maybe take a step further back and tell us the bigger picture as there might be a better solution than dynamic callbacks.

My guess is that either want to create UI elements on the fly or want to do some logic routing based on earlier input.

Yep, we want to create UI elements on the fly and those elements need to also have callbacks defined on the fly. We can’t know upfront which elements and with which callbacks the user will ask for.

A closer example of what we need to address is in the repo I posted previously above: https://github.com/Akronix/Dash-test-nesting-callbacks-in-runtime

We managed to create the UI elements dynamically, but we didn’t manage to bind their callbacks (This is the issue presented here).
OK, I just got an idea: a very poor workaround could be to define any possible selection of callbacks upfront, and then the final generated UI will get only those that are actually needed.

That is in fact the method that is recommended in the post @chriddyp linked to: programatically create every possible callback that the app I might need up front.

1 Like