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!