📣 Dash AG Grid 2.2.0 Released

Good day, All, @alistair.welch,

Let me expound a little on what the version brings to the table:

add your own event listeners -

This gives you the ability to trigger your own JS functions from any event the grid can spit out listed here, Grid Events.

interact with the grid via JS functions / clientside callbacks

This gives the ability to take this: Drag & Drop Example

And turn it into this, 3 callbacks to 1:

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

app = Dash(__name__)

df = pd.read_csv(
    "https://raw.githubusercontent.com/plotly/datasets/master/ag-grid/olympic-winners.csv"
)

columnDefs = [
    {"field": "country", "dndSource": True},
    {"field": "year"},
    {"field": "sport"},
    {"field": "gold"},
    {"field": "silver"},
    {"field": "bronze"},
]

app.layout = html.Div(
    [
        dag.AgGrid(
            columnDefs=columnDefs,
            rowData=df.to_dict("records")[:5],
            columnSize="sizeToFit",
            defaultColDef={"resizable": True, "sortable": True, "filter": True},
            dashGridOptions={"rowDragManaged": True, "animateRows": True},
            style={'width': '45%'},
            id='grid1'
        ),
        dag.AgGrid(
            columnDefs=columnDefs,
            rowData=df.to_dict("records")[6:10],
            columnSize="sizeToFit",
            defaultColDef={"resizable": True, "sortable": True, "filter": True},
            dashGridOptions={"rowDragManaged": True},
            style={'width': '45%'},
            id='grid2'
        ),
        html.Button(id='drop1', style={'display': 'none'}, n_clicks=0),
        html.Button(id='drop2', style={'display': 'none'}, n_clicks=0),
        dcc.Store(id='dropStore', storage_type='session')
    ],
    style={"margin": 20, "display": "flex"},
)

## enable drag-n-drop
app.clientside_callback(
    """
    function (p) {
        const mouseClickEvents = ['mousedown', 'click', 'mouseup'];
        function simulateMouseClick(element, args) {
            mouseClickEvents.forEach((mouseEventType) =>
                element.dispatchEvent(
                    new MouseEvent(mouseEventType, {
                        view: window,
                        bubbles: true,
                        cancelable: true,
                        buttons: 1,
                        target: element,
                        ...args,
                    })
                )
            );
            mouseClickEvents.forEach((mouseEventType) =>
                element.dispatchEvent(
                    new PointerEvent(mouseEventType, {
                        view: window,
                        bubbles: true,
                        cancelable: true,
                        buttons: 1,
                        target: element,
                        ...args,
                    })
                )
            );
        }
        var gridOrigin;
        var gridDragOver = (event) => {
            const dragSupported = event.dataTransfer.types.length;

            if (dragSupported) {
              event.dataTransfer.dropEffect = 'copy';
              event.preventDefault();
            }
          };

        var gridDragStart = (origin, event) => {
            gridOrigin = origin
        }

        var gridDrop = (target, event) => {
            event.preventDefault();

            const jsonData = event.dataTransfer.getData('application/json');
            const data = JSON.parse(jsonData);

            // if data missing or the drop target is the same as the origin, do nothing
            if (!data || target == gridOrigin) {
              return;
            }

            if (target == 'grid2') {
                dash_ag_grid.getApi('grid2').applyTransactionAsync({'add': [data]})
            } else {
                dash_ag_grid.getApi('grid1').applyTransactionAsync({'add': [data]})
            }

          };
        setTimeout(() => {
        document.querySelector('#grid1').addEventListener('dragstart', (event)=>gridDragStart('grid1', event))
        document.querySelector('#grid2').addEventListener('dragstart', (event)=>gridDragStart('grid2', event))

        document.querySelector('#grid1').addEventListener('dragover', gridDragOver)
        document.querySelector('#grid2').addEventListener('dragover', gridDragOver)
        document.querySelector('#grid2').addEventListener('drop', (event)=>gridDrop('grid2', event))
        document.querySelector('#grid1').addEventListener('drop', (event)=>gridDrop('grid1', event))
        }, 500)
        return window.dash_clientside.no_update
    }
    """,
    Output('grid2', 'id'),
    Input('grid2', 'id')
)

if __name__ == "__main__":
    app.run_server(debug=True, port=1234)

Scroll To

This gives you the ability to scroll to any visible row, column, or both with the ability to pass rowIndex, rowId (when using getRowId, or data for a row, and then the column. Very useful for bringing your users to a specific cell for them to view.

Use this to test is out:

from dash import Dash, html, Input, Output, no_update
from dash_ag_grid import AgGrid
import pandas as pd
import json


df = pd.read_csv(
        "https://raw.githubusercontent.com/plotly/datasets/master/ag-grid/olympic-winners.csv"
    )

scroll_to_inputs = [
        {"rowIndex": 100, "rowPosition": "bottom",},
        {"column": "bronze", "columnPosition": "end"},
        {"rowId": "Elizabeth Beisel12/8/2012", "rowPosition": "top"},
        {"rowIndex": 300, "rowId": "500"},
        {
            "rowIndex": 400,
            "rowId": "Ryan Bayley29/08/2004",
            "column": "athlete",
            "rowPosition": "bottom",
            "columnPosition": "start",
        },
        {
            "data": {
                "athlete": "Sabine Völker",
                "age": 28,
                "country": "Germany",
                "year": 2002,
                "date": "24/02/2002",
                "sport": "Speed Skating",
                "gold": 0,
                "silver": 2,
                "bronze": 1,
                "total": 3,
            },
            "column": "bronze",
            "columnPosition": "end",
        },
        {
            "rowIndex": 2000,
            "rowId": "Elizabeth Beisel12/8/2012",
            "data": {
                "athlete": "Elizabeth Beisel",
                "age": 19,
                "country": "United States",
                "year": 2012,
                "date": "12/8/2012",
                "sport": "Swimming",
                "gold": 0,
                "silver": 1,
                "bronze": 1,
                "total": 2,
            },
            "column": "age",
            "columnPosition": "start",
        },
    ]

app = Dash()

# basic columns definition with column defaults
columnDefs = [{"field": c} for c in df.columns]

app.layout = html.Div(
    [
        AgGrid(
            id="grid",
            columnDefs=columnDefs,
            rowData=df.to_dict("records"),
            defaultColDef={"resizable": True, "sortable": True, "filter": True},
            getRowId="params.data.athlete+params.data.date",
        ),
        html.Button(id="btn", children="Scroll To Next Position"),
        html.Div(id="scrollTo-output"),
        html.Div(id="scrollTo-input"),
    ]
)

@app.callback(
    Output("grid", "scrollTo"),
    Input("btn", "n_clicks"),
    prevent_initial_call=True,
)
def update_scrollTo(n_clicks):
    if len(scroll_to_inputs) + 1 > n_clicks:
        return scroll_to_inputs[n_clicks - 1]
    return no_update

@app.callback(
    Output("scrollTo-output", "children"),
    Input("grid", "scrollTo"),
)
def display_scrollTo(scroll_to):
    return json.dumps(scroll_to)

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

Thanks Mario Rodríguez Ibáñez!

1 Like