Skip to content

[Bug] Dash 1.5.0 inclusion of dash.DataTable and dbc.Modal breaks all callbacks #277

@christianwengert

Description

@christianwengert

Describe your context

We have a fairly complex app which was wonderfully working on Dash 1.4.0 and before. Now I updated to Dash 1.5.0 and subsequently to 1.5.1 and the fact of including a DataTable makes all callbacks not working anymore (even the clientside ones).

I managed to break it down to a minimal working example which exposes the error:

This does work (i.e. clicking on one of the "Settings" Buttons make a modal appear:

import dash
import dash_html_components as html
from dash import no_update
import dash_table as dt
from dash.dependencies import Input, Output
import dash_bootstrap_components as dbc

NODE_SETTINGS_MODAL_PREFIX = 'test'
FIELD_SETTINGS = 'field-settings'
FS_OPTIONS = 'options'


app = dash.Dash(__name__)


def layout() -> html.Div:
    div1 = html.Div(children=[
        html.Span('Node 1', id=f'label-{1}'),
        html.Button('Settings', id=f'settings-{1}'),

    ])

    div2 = html.Div(children=[
        html.Span('Node 2', id=f'label-{2}'),
        html.Button('Settings', id=f'settings-{2}'),

    ])

    layout = html.Div([
        build_node_settings_modal(),
        div1,
        div2
    ])
    return layout


def build_node_settings_modal() -> dbc.Modal:

    return dbc.Modal(
        [
            dbc.ModalHeader(html.Div([
                "Settings",
                dbc.Button(id=f"{NODE_SETTINGS_MODAL_PREFIX}-close", className="modal-close-button fas fa-times")
            ])),
            dbc.ModalBody([
                html.Div(id=f'{NODE_SETTINGS_MODAL_PREFIX}-settings', children=[
                    # dt.DataTable(
                    #     id=f'{FIELD_SETTINGS}-{FS_OPTIONS}',
                    #     columns=[{"name": i, "id": i} for i in ['value', 'label']],
                    #     data=[{'value': 'Value 1', 'label': 'Item 1'}]
                    # ),
                ])
            ]),
        ], id=NODE_SETTINGS_MODAL_PREFIX,
    )


app.layout = layout


@app.callback(
    [Output(NODE_SETTINGS_MODAL_PREFIX, "is_open"),
     Output(NODE_SETTINGS_MODAL_PREFIX, "className")],  # not a genius thing to abuse the className
    [Input(f"{NODE_SETTINGS_MODAL_PREFIX}-close", "n_clicks"),
     *[Input(f'settings-{i}', 'n_clicks') for i in [1, 2]],
     ]
)
def toggle_node_settings_modal(*args):
    if all(a is None for a in args):
        return no_update, no_update

    ctx = dash.callback_context
    triggered = ctx.triggered[0]

    if triggered['prop_id'] == f'{NODE_SETTINGS_MODAL_PREFIX}-close.n_clicks':  # Force close on Escape, close button and click beside the modal
        return False, ""

    node_id = triggered['prop_id'].split('.')[0].split('-')[1]

    return True, node_id


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


When I uncomment the dash_table part:

import dash
import dash_html_components as html
from dash import no_update
import dash_table as dt
from dash.dependencies import Input, Output
import dash_bootstrap_components as dbc

NODE_SETTINGS_MODAL_PREFIX = 'test'
FIELD_SETTINGS = 'field-settings'
FS_OPTIONS = 'options'


app = dash.Dash(__name__)


def layout() -> html.Div:
    div1 = html.Div(children=[
        html.Span('Node 1', id=f'label-{1}'),
        html.Button('Settings', id=f'settings-{1}'),

    ])

    div2 = html.Div(children=[
        html.Span('Node 2', id=f'label-{2}'),
        html.Button('Settings', id=f'settings-{2}'),

    ])

    layout = html.Div([
        build_node_settings_modal(),
        div1,
        div2
    ])
    return layout


def build_node_settings_modal() -> dbc.Modal:

    return dbc.Modal(
        [
            dbc.ModalHeader(html.Div([
                "Settings",
                dbc.Button(id=f"{NODE_SETTINGS_MODAL_PREFIX}-close", className="modal-close-button fas fa-times")
            ])),
            dbc.ModalBody([
                html.Div(id=f'{NODE_SETTINGS_MODAL_PREFIX}-settings', children=[
                    dt.DataTable(
                        id=f'{FIELD_SETTINGS}-{FS_OPTIONS}',
                        columns=[{"name": i, "id": i} for i in ['value', 'label']],
                        data=[{'value': 'Value 1', 'label': 'Item 1'}]
                    ),
                ])
            ]),
        ], id=NODE_SETTINGS_MODAL_PREFIX,
    )


app.layout = layout


@app.callback(
    [Output(NODE_SETTINGS_MODAL_PREFIX, "is_open"),
     Output(NODE_SETTINGS_MODAL_PREFIX, "className")],  # not a genius thing to abuse the className
    [Input(f"{NODE_SETTINGS_MODAL_PREFIX}-close", "n_clicks"),
     *[Input(f'settings-{i}', 'n_clicks') for i in [1, 2]],
     ]
)
def toggle_node_settings_modal(*args):
    if all(a is None for a in args):
        return no_update, no_update

    ctx = dash.callback_context
    triggered = ctx.triggered[0]

    if triggered['prop_id'] == f'{NODE_SETTINGS_MODAL_PREFIX}-close.n_clicks':  # Force close on Escape, close button and click beside the modal
        return False, ""

    node_id = triggered['prop_id'].split('.')[0].split('-')[1]

    return True, node_id


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

The callback won't fire anymore (and there is not even a callback related to the table!)
So no modal showing up

  • replace the result of pip list | grep dash below
dash                      1.5.1  
dash-bootstrap-components 0.7.2  
dash-canvas               0.0.11 
dash-core-components      1.4.0  
dash-cytoscape            0.1.1  
dash-html-components      1.0.1  
dash-renderer             1.2.0  
dash-table                4.5.0  

  • if frontend related, tell us your Browser, Version and OS

    • OS: OSX
    • Browser Chrome, Vivaldi, Safari

Describe the bug

Having a DataTable in the layout breaks all callbacks, i.e callbacks are not firing at all anymore
Uncommenting the use of DataTable makes everything OK

Expected behavior

Callback working

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions