Description
When a grid is created with a sort applied at init time (e.g. via
dashGridOptions.initialState.sort.sortModel), the browser console
shows an uncaught TypeError at grid creation:
AgGrid.react.js:735 Uncaught TypeError: Cannot read properties of
null (reading 'isDestroyed')
at AgGrid.react.js:735:22
at main.esm.mjs:41889:13
at qS.wrapOutgoing (main.esm.mjs:34897:39)
...
at j.flushAsyncQueue (main.esm.mjs:114:15)
One error is emitted per grid that has an initial sort. The error is
benign in practice (only the first columnState sync back to Dash is
skipped for that event; subsequent sortChanged events work normally),
but it pollutes the console on every page load.
Environment
- dash-ag-grid 32.3.2 (also verified present in 32.3.4 and 35.2.0
sources, see below)
- dash 4.0.0
- AG Grid community v32 (bundled)
- Chrome, macOS
Root cause
In src/lib/fragments/AgGrid.react.js, the onSortChanged handler is
the only event handler that dereferences gridApi without a null
guard (v32.3.2 line 735; still identical in v35.2.0 line 754):
const onSortChanged = useCallback(() => {
const {rowModelType} = props;
const propsToSet = {};
if (rowModelType === 'clientSide') {
propsToSet.virtualRowData = virtualRowData();
}
if (!gridApi.isDestroyed()) { // <-- gridApi can be null here
propsToSet.columnState = JSON.parse(
JSON.stringify(gridApi.getColumnState())
);
}
customSetProps(propsToSet);
}, [props.rowModelType, virtualRowData, gridApi, customSetProps]);
All sibling handlers use the guarded form
gridApi && !gridApi?.isDestroyed() (e.g. onPaginationChanged,
onRowDataUpdated), and updateColumnState has an early
if (!gridApi) return;.
Why gridApi is null when the handler fires: AG Grid v32 dispatches
grid events asynchronously (dispatchAsync -> setTimeout ->
flushAsyncQueue). When a grid initializes with a sort (initialState
sortModel), a sortChanged event is queued during grid creation
(ColumnApplyStateService dispatches it when applying the initial sort
state). The queue is flushed on a setTimeout tick that can run before
React has committed the setGridApi state update from onGridReady,
so the onSortChanged closure still sees gridApi === null and the
unguarded gridApi.isDestroyed() throws.
Reproduction
import dash_ag_grid as dag
from dash import Dash
app = Dash(__name__)
app.layout = dag.AgGrid(
id="grid",
rowData=[{"a": i, "b": 10 - i} for i in range(5)],
columnDefs=[{"field": "a"}, {"field": "b"}],
dashGridOptions={
"initialState": {
"sort": {"sortModel": [{"colId": "b", "sort": "asc"}]}
},
},
)
if __name__ == "__main__":
app.run(debug=True)
Load the page with the browser console open: the TypeError appears
once at grid creation. With two such grids in the layout, it appears
twice, with identical stacks.
Note: the error does NOT depend on persisted column state
(localStorage cleared -> error unchanged); any sort applied at grid
init triggers it.
Suggested fix
Align onSortChanged with the guard used by every other handler:
if (gridApi && !gridApi?.isDestroyed()) {
The same unguarded line is still present in the latest sources
(v35.2.0, src/lib/fragments/AgGrid.react.js:754), so the fix applies
to the current line as well as the 32.x maintenance branch.
Description
When a grid is created with a sort applied at init time (e.g. via
dashGridOptions.initialState.sort.sortModel), the browser consoleshows an uncaught TypeError at grid creation:
One error is emitted per grid that has an initial sort. The error is
benign in practice (only the first
columnStatesync back to Dash isskipped for that event; subsequent sortChanged events work normally),
but it pollutes the console on every page load.
Environment
sources, see below)
Root cause
In
src/lib/fragments/AgGrid.react.js, theonSortChangedhandler isthe only event handler that dereferences
gridApiwithout a nullguard (v32.3.2 line 735; still identical in v35.2.0 line 754):
All sibling handlers use the guarded form
gridApi && !gridApi?.isDestroyed()(e.g.onPaginationChanged,onRowDataUpdated), andupdateColumnStatehas an earlyif (!gridApi) return;.Why
gridApiis null when the handler fires: AG Grid v32 dispatchesgrid events asynchronously (dispatchAsync -> setTimeout ->
flushAsyncQueue). When a grid initializes with a sort (initialState
sortModel), a
sortChangedevent is queued during grid creation(ColumnApplyStateService dispatches it when applying the initial sort
state). The queue is flushed on a setTimeout tick that can run before
React has committed the
setGridApistate update fromonGridReady,so the
onSortChangedclosure still seesgridApi === nulland theunguarded
gridApi.isDestroyed()throws.Reproduction
Load the page with the browser console open: the TypeError appears
once at grid creation. With two such grids in the layout, it appears
twice, with identical stacks.
Note: the error does NOT depend on persisted column state
(localStorage cleared -> error unchanged); any sort applied at grid
init triggers it.
Suggested fix
Align
onSortChangedwith the guard used by every other handler:The same unguarded line is still present in the latest sources
(v35.2.0,
src/lib/fragments/AgGrid.react.js:754), so the fix appliesto the current line as well as the 32.x maintenance branch.