Dash AG Grid: How to Drag Drop between grids

@alistair.welch,

Here is a working example of how to do this without any additional options from the grid:

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;
            }
            
            // store data for use in transfer
            sessionStorage.setItem('dropStore', jsonData)

            if (target == 'grid2') {
                simulateMouseClick(document.querySelector('#drop2'))
            } else {
                simulateMouseClick(document.querySelector('#drop1'))
            }
            
          };
        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')
)

app.clientside_callback(
    """
    function (n) {
        data = JSON.parse(sessionStorage.getItem('dropStore'))
        
        //remove stored session data
        sessionStorage.setItem('dropStore', null)
        return {'add': [data]}
    }
    """,
    Output('grid2', 'rowTransaction'),
    Input('drop2', 'n_clicks'),
    prevent_initial_call=True
)

app.clientside_callback(
    """
    function (n) {
        data = JSON.parse(sessionStorage.getItem('dropStore'))
        
        //remove stored session data
        sessionStorage.setItem('dropStore', null)
        return {'add': [data]}
    }
    """,
    Output('grid1', 'rowTransaction'),
    Input('drop1', 'n_clicks'),
    prevent_initial_call=True
)

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