AG-Grid Master Detail: how to access detail-grid data in a callbak

I’m using Master Detail feature to display some nested data. I want to perform update and delete operations on detail grid rows. For the same I want to select a detail-row and access it in a callback. I’ve got no help from the documentation. Is there a way I can access detail-row data in callbacks? Thank you.

Hello @NMamathaG,

You can access the detail grid’s api by using the master grid’s rowGroupOpened event listener, check this example:

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

import os

import time

app = Dash(__name__)
masterColumnDefs = [
    {
        "headerName": "Country",
        "field": "country",
        "cellRenderer": "agGroupCellRenderer",
    },
    {"headerName": "Region", "field": "region"},
    {"headerName": "Population", "field": "population"},
]

detailColumnDefs = [
    {"headerName": "City", "field": "city"},
    {"headerName": "Pop. (City proper)", "field": "population_city"},
    {"headerName": "Pop. (Metro area)", "field": "population_metro"},
]

rowData = [
    {
        "country": "China",
        "region": "Asia",
        "population": 1411778724,
        "cities": [
            {"city": "Shanghai", "population_city": 24870895, "population_metro": "NA"},
            {"city": "Beijing", "population_city": 21893095, "population_metro": "NA"},
            {
                "city": "Chongqing",
                "population_city": 32054159,
                "population_metro": "NA",
            },
        ],
    },
    {
        "country": "India",
        "region": "Asia",
        "population": 1383524897,
        "cities": [
            {
                "city": "Delhi",
                "population_city": 16753235,
                "population_metro": 29000000,
            },
            {
                "city": "Mumbai",
                "population_city": 12478447,
                "population_metro": 24400000,
            },
            {
                "city": "Kolkata",
                "population_city": 4496694,
                "population_metro": 14035959,
            },
        ],
    },
    {
        "country": "United States",
        "region": "Americas",
        "population": 332593407,
        "cities": [
            {
                "city": "New York",
                "population_city": 8398748,
                "population_metro": 19303808,
            },
            {
                "city": "Los Angeles",
                "population_city": 3990456,
                "population_metro": 13291486,
            },
            {
                "city": "Chicago",
                "population_city": 2746388,
                "population_metro": 9618502,
            },
        ],
    },
    {
        "country": "Indonesia",
        "region": "Asia",
        "population": 271350000,
        "cities": [
            {
                "city": "Jakarta",
                "population_city": 10154134,
                "population_metro": 33430285,
            },
        ],
    },
]


app.layout = html.Div(
    [
        dag.AgGrid(
            enableEnterpriseModules=True,
            id="nested-grid-detail-table-request-2",
            columnDefs=masterColumnDefs,
            rowData=rowData,
            columnSize="sizeToFit",
            masterDetail=True,
            detailCellRendererParams={
                "detailGridOptions": {
                    "columnDefs": detailColumnDefs,
                    "defaultColDef": {'editable': True}
                },
                "detailColName": "cities",
                "suppressCallback": True,
            },
            dashGridOptions={"detailRowAutoHeight": True},
            getRowId='params.data.country'
        ),
        html.Div(id='output')
    ]
)

app.clientside_callback(
    """(id) => {
        dash_ag_grid.getApiAsync(id).then((grid) => {
            grid.addEventListener('rowGroupOpened', (em) => {
                if (em.node.detailNode && em.expanded) {
                    gridDetail = em.node.detailNode.detailGridInfo
                    gridDetail.api.addEventListener('cellValueChanged', 
                    (ed) => {
                    const newChange = {...ed, node: {id:`${gridDetail.id} - ${ed.node.id}`}}
                    em.api.getGridOption('onCellValueChanged')(newChange)
                    })
                }
            })
        })
        return window.dash_clientside.no_update
    }""",
    Output('output', 'id'),
    Input('nested-grid-detail-table-request-2', 'id')
)

app.clientside_callback(
    """function (d) {
        return JSON.stringify(d)
    }""",
    Output('output', 'children'),
    Input('nested-grid-detail-table-request-2', 'cellValueChanged')
)


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

In this example, I utilize the master grid’s options that is hooked up to the onCellValueChanged and recreate the event with a modification to be able to flag that this cellValueChanged is coming from the detail grid. Then I retrigger the event.

This could be an unneeded step once Plotly releases a version of dash that will let you setProps directly from JS.

dag-docs

3 Likes

Thanks a ton for the quick solution. I’ll try and implement a similar thing for my dashboard.

1 Like

Hello,
Could you please explain the line :
em.api.getGridOption(‘onCellValueChanged’)(newChange)

We do not see in the getGridOption documentation “onCellValueChanged’” as a option for Grid.

getGridOption is available on the gridApi on the underlying AG grid.

Yes I saw that in the documentation,
My issue is that I do not find events such as 'onCellValueChanged’ in the list of Grid options that can be accessed with getGridOption.
Is there somewhere a list of events accessible with getGridOptions ?

Grid options allows you to access any grid option that has been set.

Events can be found here:

Most events can be passed as grid options with the pre of on. So, event cellValueChanged turns into onCellValueChanged as a prop.

However, it is important to note that you cannot directly pass new event listeners to the grid in this fashion. We instead allow you to pass keys to eventListeners, eg eventListeners: {“cellValueChanged”:[”mycustomfunction(params)”] and these are added upon grid ready event.

1 Like