Triggering a callback with a dropdown selection from datatable cell

Hello, I have a datable with a dropdown menu within a column of cells. I’m trying to trigger a callback when a user makes a selection from the dropdown menu. I’ve tried 'Input(‘datatable’, ‘dropdown’) and ‘active_cell’ with no luck. Any other ideas? Here is a simple reproduction of my problem

import dash
from dash import Dash, html, dash_table, callback_context
from dash.exceptions import PreventUpdate
from dash import Input, Output, State, Patch, ctx, html

app = Dash(__name__)


table_contents = ['DrugA', 'DrugB', 'DrugC']

app.layout = html.Div([
    dash_table.DataTable(
        id='datatable',
        columns=[
            {'name': 'Drug', 'id': 'drug'},
            {'name': 'Delivery', 'id': 'delivery', 'presentation': 'dropdown'},
        ],
        data=[
            {'drug': name, 'delivery': 'Infusion pump' if name == 'DrugA' else 'Bolus'}
            for name in table_contents
        ],
        editable=True,
        row_deletable=True,
        dropdown={
            'delivery': {
                'options': [
                    {'label': 'Bolus', 'value': 'Bolus'},
                    {'label': 'Infusion pump', 'value': 'Infusion pump'},
                    {'label': 'Slow injection', 'value': 'Slow injection'}
                ],
            },
        },
    ),
    html.Div(id='selected-delivery-output'),  # Output element to display selected items
], className="dbc_light", style={'background-color': 'white'})

@app.callback(
    Output('selected-delivery-output', 'children'),
    [dash.dependencies.Input('datatable', 'dropdown')],
    prevent_initial_call=True
)
def display_selected_delivery(dropdown):
    print(dropdown)
    return dash.no_update

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

hi @romarcin
I wasn’t able to get it to work with Dash DataTable, but the docs have a dropdown example with Dash AG Grid row menu:

import dash_ag_grid as dag
from dash import Dash, Input, Output, html, dcc, callback

app = Dash(__name__)

columnDefs = [
    {"headerName": "Make", "field": "make", "sortable": True},
    {"headerName": "Model", "field": "model"},
    {"headerName": "Price", "field": "price"},
    {"headerName": "Menu", "field": "menu", "cellRenderer": "rowMenu"},
]

rowData = [
    {
        "make": "Toyota",
        "model": "Celica",
        "price": 35000,
        "menu": [
            {"label": "Option 1", "value": 1},
            {"label": "Option 2", "value": 2},
            {"label": "Option 3", "value": 3},
        ],
    },
    {
        "make": "Ford",
        "model": "Mondeo",
        "price": 32000,
        "menu": [
            {"label": "Option 4", "value": 4},
            {"label": "Option 5", "value": 5},
            {"label": "Option 6", "value": 6},
        ],
    },
    {
        "make": "Porsche",
        "model": "Boxster",
        "price": 72000,
        "menu": [
            {"label": "Option 7", "value": 7},
            {"label": "Option 8", "value": 8},
            {"label": "Option 9", "value": 9},
        ],
    },
]


grid = dag.AgGrid(
    id="cellrenderer-grid",
    columnSize="sizeToFit",
    getRowId="params.data.make",
    columnDefs=columnDefs,
    rowData=rowData,
)

app.layout = html.Div(
    [
        dcc.Markdown("Example: Row Menu Component"),
        grid,
        html.P(id="cellrenderer-data"),
    ],
    style={"margin": 20},
)


@callback(
    Output("cellrenderer-data", "children"),
    Input("cellrenderer-grid", "cellRendererData"),
)
def show_click_data(data):
    if data:
        return (
            "You selected option {} from the colId {}, rowIndex {}, rowId {}.".format(
                data["value"],
                data["colId"],
                data["rowIndex"],
                data["rowId"],
            )
        )
    return "No menu item selected."


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

That will work. Thank you so much!

Hi @romarcin

You can also use the Grid’s Cell Editor:

Here’s another example where the dropdown has different options depending on the row:

Or even create a custom component using the Dash Manetine Components library like in this post:

2 Likes