How to use the AG Grid API with Dash
Overview
In this post, I’ll cover:
- Accessing the Grid’s API in a Dash Clientside Callback
- Determining the Correct AG Grid Docs Version for Dash AG Grid
- Examples: Flashing Cells using the Grid’s API
- Differentiating Between Dash AG Grid Functions:
getApiAsync
andgetApi
Using the Grid’s API
The grid is highly configurable and has an extensive API. Not all AG Grid props and methods are defined as Dash props, but you can still use them.
Many advanced features require using the Grid’s API. You can access the grid’s API in Dash using getApi
or
getApiAsync
in a clientside callback. I’ll use getApiAsync
in the next couple examples, then later explain the
difference between the functions.
Determining the Correct AG Grid Docs Version for Dash AG Grid
Note that not all the grid’s features are included in the Dash docs, so it’s necessary to also refer to AG Grid docs.
Given AG Grid’s frequent releases, you may often find it necessary to use an archived version of their docs.
Starting with Dash AG Grid V31.0.0, you can find your grid version by using dag.grid_version
import dash_ag_grid as dag
print("dash-ag-grid version: ", dag.__version__)
print("AG Grid version: ", dag.grid_version)
Now, navigate to the AG Grid docs archive to find the appropriate documentation link. If you can’t locate an exact match, use the version one minor step lower.
In the following examples, I’ll show how to use the grid’s API to flash cells (a feature that is not yet in the Dash docs, but coming soon!). It’s important to use the archived version of AG Grid docs, because the in a later version, AG Grid changed some prop names.
In this tutorial I’m using Dash AG Grid V31.0.1 which uses grid version 31.0.3.
Please follow along using the AG Grid docs for Flashing Cells React Data Grid: Flashing Cells. This uses the AG Grid archived docs for V31.0.2
Example 1: Flashing Cells using the Grid’s API
The grid can flash cells to highlight data changes. This is a great visual indicator to users of the grid who want data changes to be noticed.
Here I’m just going to provide a Dash version of the examples from the AG Grid docs. Please refer to the AG Grid docs for all the details about the flashCells
method.
import dash_ag_grid as dag
from dash import Dash, html, Input, Output, clientside_callback
import random
import pandas as pd
df = pd.DataFrame({
'a': [random.randint(0, 10000) for _ in range(20)],
'b': [random.randint(0, 10000) for _ in range(20)],
'c': [random.randint(0, 10000) for _ in range(20)],
'd': [0] * 20,
'e': [0] * 20,
'f': [0] * 20
})
app = Dash()
app.layout = html.Div(
[
html.Button("Update Some Data", id="btn-flash-update"),
html.Button("Flash One Cell", id="btn-flash-cell"),
html.Button("Flash Two Rows", id="btn-flash-rows"),
html.Button("Flash Two Columns", id="btn-flash-cols"),
dag.AgGrid(
id="grid-flash-cells",
rowData=df.to_dict("records"),
columnDefs=[{"field": i } for i in df.columns],
defaultColDef={"flex": 1,"cellClass": 'align-right', "enableCellChangeFlash": True}
)
]
)
# Update some data
clientside_callback(
"""async (n) => {
if (n) {
const gridApi = await dash_ag_grid.getApiAsync("grid-flash-cells")
var rowCount = gridApi.getDisplayedRowCount();
// pick 20 cells at random to update
for (var i = 0; i < 20; i++) {
var row = Math.floor(Math.random() * rowCount);
var rowNode = gridApi.getDisplayedRowAtIndex(row);
var col = ['a', 'b', 'c', 'd', 'e', 'f'][i % 6];
rowNode.setDataValue(col, Math.floor(Math.random() * 10000));
}
}
return dash_clientside.no_update
}""",
Output("btn-flash-update", "id"),
Input("btn-flash-update", "n_clicks"),
)
# Flash cell
clientside_callback(
"""async (n) => {
if (n) {
const gridApi = await dash_ag_grid.getApiAsync("grid-flash-cells")
// flash row 4 col 'c'
var rowNode = gridApi.getDisplayedRowAtIndex(4);
gridApi.flashCells({ rowNodes: [rowNode], columns: ['c'] });
}
return dash_clientside.no_update
}""",
Output("btn-flash-cell", "id"),
Input("btn-flash-cell", "n_clicks"),
)
# Flash 2 rows
clientside_callback(
"""async (n) => {
if (n) {
const gridApi = await dash_ag_grid.getApiAsync("grid-flash-cells")
// pick row 4 and 5
var rowNode1 = gridApi.getDisplayedRowAtIndex(4);
var rowNode2 = gridApi.getDisplayedRowAtIndex(5);
// flash whole row, so leave column selection out
gridApi.flashCells({ rowNodes: [rowNode1, rowNode2] });
}
return dash_clientside.no_update
}""",
Output("btn-flash-rows", "id"),
Input("btn-flash-rows", "n_clicks"),
)
# Flash 2 columns
clientside_callback(
"""async (n) => {
if (n) {
const gridApi = await dash_ag_grid.getApiAsync("grid-flash-cells");
gridApi.flashCells({ columns: ['c', 'd'] });
}
return dash_clientside.no_update;
}""",
Output("btn-flash-cols", "id"),
Input("btn-flash-cols", "n_clicks"),
)
if __name__ == "__main__":
app.run(debug=True)
Let’s take a closer look at the callback function to flash the columns.
In the AG Grid docs (React), they get the grid’s API using gridRef.current.api
:
const onFlashTwoColumns = useCallback(() => {
// flash whole column, so leave row selection out
gridRef.current.api.flashCells({ columns: ['c', 'd'] });
}, []);
In the Dash app above, getApiAsync
is used to get the grid API. Note that you need to provide the id of grid. In this app the id is "grid-flash-cells"
const gridApi = await dash_ag_grid.getApiAsync("grid-flash-cells")
Here’s the Dash callback to flash 2 columns:
clientside_callback(
"""async (n) => {
if (n) {
const gridApi = await dash_ag_grid.getApiAsync("grid-flash-cells")
// flash whole column, so leave row selection out
gridApi.flashCells({ columns: ['c', 'd'] });
}
return dash_clientside.no_update
}""",
Output("btn-flash-cols", "id"),
Input("btn-flash-cols", "n_clicks"),
)
Once you have defined the gridApi
, you’ll have access to all the grid API methods in the Dash clientside callback.
Here’s an example of how to flash the ‘c’ and ‘d’ columns:
gridApi.flashCells({ columns: ['c', 'd'] });
This will get row number 4. See how this is used in other clientside callbacks in the app above.
gridApi.getDisplayedRowAtIndex(4);
Example 2 How Flashing Works
See details about this example in the AG Grid docs
This example shows how to further configure the flashing by changing the flash background color with CSS and adjusting the length of the flash in the grid’s flashCells
API.
This also shows how important it is to use the correct version of the docs. In AG Grid V31.1.0 they changed the prop names from flashDelay
to flashDuration
and from fadeDelay
to fadeDuration
. However, those new props aren’t available in our version (31.0.3), so we need to continue to use the old prop names.
Here’s the CSS to change the flash background color:
.flash .ag-theme-alpine,
.flash .ag-theme-alpine-dark {
--ag-value-change-value-highlight-background-color: #cc222244;
}
import dash_ag_grid as dag
from dash import Dash, html, Input, Output, clientside_callback
import random
import pandas as pd
print("dash-ag-grid version: ", dag.__version__)
print("AG Grid version: ", dag.grid_version)
df = pd.DataFrame({
'a': [random.randint(0, 10000) for _ in range(20)],
'b': [random.randint(0, 10000) for _ in range(20)],
'c': [random.randint(0, 10000) for _ in range(20)],
'd': [0] * 20,
'e': [0] * 20,
'f': [0] * 20
})
app = Dash()
app.layout = html.Div(
[
html.Button("Update Some Data", id="btn-flash-update-custom"),
html.Button("Flash Two Rows", id="btn-flash-rows-custom"),
dag.AgGrid(
id="grid-flash-cells-custom",
rowData=df.to_dict("records"),
columnDefs=[{"field": i } for i in df.columns],
defaultColDef={"flex": 1,"cellClass": 'align-right', "enableCellChangeFlash": True},
dashGridOptions={"cellFlashDelay": 2000, "cellFadeDelay": 500}
)
], className="flash",
)
# Update some data
clientside_callback(
"""async (n) => {
if (n) {
const gridApi = await dash_ag_grid.getApiAsync("grid-flash-cells-custom")
var rowCount = gridApi.getDisplayedRowCount();
// pick 20 cells at random to update
for (var i = 0; i < 20; i++) {
var row = Math.floor(Math.random() * rowCount);
var rowNode = gridApi.getDisplayedRowAtIndex(row);
var col = ['a', 'b', 'c', 'd', 'e', 'f'][i % 6];
rowNode.setDataValue(col, Math.floor(Math.random() * 10000));
}
}
return dash_clientside.no_update
}""",
Output("btn-flash-update-custom", "id"),
Input("btn-flash-update-custom", "n_clicks"),
)
# Flash 2 rows
clientside_callback(
"""async (n) => {
if (n) {
const gridApi = await dash_ag_grid.getApiAsync("grid-flash-cells-custom")
// pick row 4 and 5
var rowNode1 = gridApi.getDisplayedRowAtIndex(4);
var rowNode2 = gridApi.getDisplayedRowAtIndex(5);
// flash whole row, so leave column selection out
gridApi.flashCells({
rowNodes: [rowNode1, rowNode2],
flashDelay: 3000,
fadeDelay: 2000,
});
}
return dash_clientside.no_update
}""",
Output("btn-flash-rows-custom", "id"),
Input("btn-flash-rows-custom", "n_clicks"),
)
if __name__ == "__main__":
app.run(debug=True)
Understanding getApi
and getApiAsync
in Dash AG Grid
In Dash AG Grid, there are two function for retrieving the grid API: getApi
and getApiAsync
.
Since most of us use Python more than JavaScript, here are some great articles from MDN on the difference between synchronous and asynchronous functions in JavaScript:
getApi
Method:
You can use getApi
with a regular (synchronous) JavaScript function. It simply checks one time if the grid is ready and returns either the grid’s API or an error. This means that if the Dash callback is triggered when the app starts and the grid is not ready, you will get the error.
Here’s an example to illustrate. This callback will be triggered when the app starts and the grid won’t be ready.
# This uses getApi before the grid is ready and it won't work:
clientside_callback(
""" () => {
const gridApi = dash_ag_grid.getApi("grid-flash-cells")
gridApi.flashCells({ columns: ['c', 'd'] });
return dash_clientside.no_update
}""",
Output("btn-flash-cols", "id"),
Input("btn-flash-cols", "n_clicks"),
)
getApiAsync
Method:
The getApiAsync
function is asynchronous and returns a promise. It uses a timeout and will wait for up to 2 minutes for the grid to be ready before it sends an error. (If it takes longer than 2 minutes to load the grid, you should probably be using background callbacks).
Here’s some info from the MDN article:
The
async
keyword gives you a simpler way to work with asynchronous promise-based code. Addingasync
at the start of a function makes it an async function.Inside an async function, you can use the
await
keyword before a call to a function that returns a promise. This makes the code wait at that point until the promise is settled, at which point the fulfilled value of the promise is treated as a return value, or the rejected value is thrown.
This enables you to write code that uses asynchronous functions but looks like synchronous code.
This is the same function as above, but it uses getApiAsync
. In this example, even though the callback is triggered when the app starts, it will wait for the grid to render and you will not see the error.
# Flash 2 columns when the app starts using getApiAsync
clientside_callback(
"""async () => {
const gridApi = await dash_ag_grid.getApiAsync("grid-flash-cells")
gridApi.flashCells({ columns: ['c', 'd'] });
return dash_clientside.no_update
}""",
Output("btn-flash-cols", "id"),
Input("btn-flash-cols", "n_clicks"),
)
Next Steps
- When migrating to future version of Dash AG Grid, be sure to update the prop names in the
flashCells
API - If you’ve found Dash AG Grid valuable, show your support by starring us on GitHub!
.
- Head over to Dash AG Grid Examples to see these examples live and for other helpful tutorials
Happy Coding!