Black Lives Matter. Please consider donating to Black Girls Code today.
Dash HoloViews is now available! Check out the docs.

Dynamic callback function setup inside an existing callback function

Hi, everyone,

I had some problem with layout and dynamic callback function setup.

I’m trying to write a callback funtion A to return a new html.Div dynamically to an output in layout.

But in this new html.Div could have different output settings due to the input of callback funtion A. So I need to dynamically define new callback functions (B or C or, D due to different output settings). The problem is, I can not define such callback functions (B or C or, D) before callback funtion A has been returned. (Or an error “no such ids existing in the layout” will be thrown out)

PANEL_SEL_FUNC = {
                    FLEET_DISPLAY_TABS[0]: call_overview_panel,
                    FLEET_DISPLAY_TABS[1]: call_alerm_panel,
                    FLEET_DISPLAY_TABS[2]: call_maintenence_panel,
                    FLEET_DISPLAY_TABS[3]: call_usage_panel
}
app.layout = html.Div(
    children = [
        # The panel on right handside of mean
        html.Div(
            children = [
                dcc.Tabs(
                    id="fleet_display_tabs",
                    tabs=[
                            {"label": i, "value": i} for i in FLEET_DISPLAY_TABS
                    ],
                    value=FLEET_DISPLAY_TABS[0]
                ),
                html.Div(id="fleet_display_tabs_output")
            ]
        )
    ]
)

@app.callback(
    Output('fleet_display_tabs_output', 'children'),
    [Input('fleet_display_tabs', 'value')]
)
def display_fleet_panel(fleet_display_tabs_val):
    return PANEL_SEL_FUNC[fleet_display_tabs_val]() ## Assume we call call_overview_panel below here

def build_KPIs(
                event_id,
                KPI_name,
                KPI_id,
                KPI_percentage_id,
                float_type):
    return html.Div(
                id=event_id,
                children=[
                    html.H5(KPI_name),
                    html.Div(KPI_id, id=KPI_id),
                    html.Div(KPI_percentage_id, id=KPI_percentage_id)],
                style={"width":"24%","float":float_type,"display":"inline-block"})

def call_overview_panel():
    overview_panel = html.Div(
        id="overview_panel",
        children = [
            html.Div(
                children=[
                    #create row of 4 divs
                    build_KPIs(
                                kpi_config[0],
                                kpi_config[1],
                                kpi_config[2],
                                kpi_config[3],
                                kpi_config[4]) for kpi_config in KPI_EVENT_LIST_2
                ]
            ),
        ]
    )

    for kpi_config in KPI_EVENT_LIST_1 + KPI_EVENT_LIST_2:
        @app.callback(
            Output(kpi_config[2], "children"),
            [Input("dropdown_car_type","value")]
        )
        def pass_KPI_value(car_type):
            return "succ"
         
    return overview_panel

solution:
I can think about now, is to setup all possible new html.Div blocks due to different setting in advance and change the “hidden” properties of them dynamically by write new callback function.

But I sitll curious about if I can solve this problem by dynamically setup the callback functions (B or C or, D) because it makes code more readable and efficient.

Could anyone help? Thank any of you give a comment in this topic in advance.

Cheers,
Zhiwei

1 Like

You have to register all callback functions that you will need before the Dash server starts, so this means that you can’t have dynamically defined callbacks in response to user input currently.

So yeah, you’re options are to make sure that a callback either: inserts the needed elements or toggles their visibility before the callback that uses them is triggered.

3 Likes

A post was split to a new topic: Toggle the visibility before the main callback is triggered - Dash Tabs

Is there any plans to change this behaviour in the future? For more complicated apps with dynamically rendered UIs, this design choice (or issue) seems like a major limitation.

3 Likes