Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] Dash 1.5.1 Datatable disables all callbacks #998

Closed
christianwengert opened this issue Nov 4, 2019 · 3 comments
Closed

[BUG] Dash 1.5.1 Datatable disables all callbacks #998

christianwengert opened this issue Nov 4, 2019 · 3 comments

Comments

@christianwengert
Copy link

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

@christianwengert christianwengert changed the title [BUG] Dash 1.5.0 Datatable disables all callbacks [BUG] Dash 1.5.1 Datatable disables all callbacks Nov 4, 2019
@christianwengert
Copy link
Author

I found the following: When replacing the dash_bootstrap_components.Modal.is_open property with a simple dash_html_components.div.style property:

"""

"""
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 html.Div(
        [
            html.Div([
                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,
        style={'display': 'none'}
    )


app.layout = layout


@app.callback(
    [Output(NODE_SETTINGS_MODAL_PREFIX, "style"),
     Output(NODE_SETTINGS_MODAL_PREFIX, "className")],  # not a genius thing to abuse the className
    [
     *[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 {'display': 'none'}, ""

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

    return {'display': 'block'}, node_id


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

Everything works as expected => So no bug in dash, but in dash bootstrap components. I will close this issue and reopen it at dbc

@alexcjohnson
Copy link
Collaborator

This may just be #995

@christianwengert
Copy link
Author

With Dash 1.6.0 still the same problem

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants