Batch editing lets you queue edits across multiple cells or rows, then commit or discard them all at once.
Enabling Batch Editing Copy Link
- Start — call
api.startBatchEdit()to start a batch edit. - Edit — make one or more edits. Pending values are displayed in the grid but not written to the data.
- Commit or cancel — call
api.commitBatchEdit()to apply all pending edits to the data. To discard the pending edits and revert the display to the original data values callapi.cancelBatchEdit().
Batch editing is only available via the API and only compatible with the Client-Side Row Model.
Batch Editing Lifecycle Copy Link
Cell and row editing events (cellEditingStarted, cellEditingStopped, etc.) fire normally when editors open and close.
The key difference is that cellValueChanged and rowValueChanged are deferred — they only fire when commitBatchEdit() is called. If cancelBatchEdit() is called instead, pending values are discarded and no value-changed events fire.
Two batch-specific events are also available:
Fired when the first edit is made after api.startBatchEdit() is called.
This event fires lazily — not immediately on api.startBatchEdit(), but on the first cell value change or editor open within the batch session. |
Batch editing has stopped (when batch editing is enabled). Contains a list of edits if the batch was committed via api.commitBatchEdit(). |
Pending Values Copy Link
Edits made during a batch are stored as pending values — they are not applied to the data until committed.
- Display features (cell rendering, copy/paste, fill handle) reflect pending values immediately.
- Data features (sorting, filtering, grouping, aggregation) use committed data until the batch is committed.
- Clipboard paste — pasted values during a batch are staged as pending edits rather than being written to data.
- On cancel, all pending values are discarded and the grid reverts to the original data.
Reading Values Copy Link
There are two main APIs to read cell values but they differ in their default behaviour.
rowNode.getDataValue()— defaults tofrom: 'data'(ignores pending edits). Use for data-facing reads.api.getCellValue()— defaults tofrom: 'edit'(shows pending edits). Use for UI-facing reads.
rowNode.getDataValue() Copy Link
Returns the data value from the rowNode for the specified column. By default, returns committed data ignoring any pending edits. For group rows, returns aggregated values or the group key. For formula cells, returns the computed result. To get the displayed value (with formatting and value formatter applied), use api.getCellValue() instead. In Pivot Mode, pivot columns on leaf rows resolve to their underlying value column. The from parameter controls value resolution. |
The table below shows the impact of the from parameter on the value that is returned. The first non-empty source reading left-to-right is used. The Aggregation column only applies to group rows with an aggFunc.
from | Active Editor (if editing) | Pending Batch (if batching) | Aggregation (if present) | Committed Data |
|---|---|---|---|---|
'data' (default) | — | — | Agg value | Fallback |
'edit' | Used if present | Used if no editor | Agg value | Fallback |
'batch' | — | Used if present | Agg value | Fallback |
'value' | — | — | Scalar (unwrapped) | Fallback |
'data-raw' | — | — | — | Always used |
Aggregate Values
'value'— same as'data', but unwraps the aggregation result returned byavgandcountto its scalar value.'data-raw'— same as'data'but skips aggregation results (rowNode.aggData). For group rows the valueGetter or field value is returned instead, which is typicallyundefinedsince group rows do not hold leaf data.
Example getDataValue() Copy Link
// 42 (original value)
api.startBatchEdit(); // Start Batch
rowNode.setDataValue('price', 99, 'batch'); // Edit value to 99
rowNode.getDataValue('price') // 42 (original data, default 'data')
rowNode.getDataValue('price', 'batch'); // 99 (pending value)
rowNode.getDataValue('price', 'edit'); // 99 (no editor open, same as 'batch')
api.commitBatchEdit(); // Commit Batch
rowNode.getDataValue('price'); // 99 (now committed)
// Column 'revenue' uses aggFunc: 'avg' — average is 420 across 3 rows
groupRowNode.getDataValue('revenue'); // aggregation result object
groupRowNode.getDataValue('revenue', 'value'); // 420 (scalar)
groupRowNode.getDataValue('revenue', 'data-raw'); // undefined (skips aggData; group row has no raw field)
api.getCellValue() Copy Link
Gets the cell value for the given column and rowNode (row). Will return the cell value or the formatted value depending on the value of params.useFormatter. |
from | Active Editor | Pending Batch | Aggregation | Committed Data |
|---|---|---|---|---|
'edit' (default) | Used if present | Used if no editor | Agg value | Fallback |
'batch' | — | Used if present | Agg value | Fallback |
'data' | — | — | Agg value | Fallback |
Example getCellValue() Copy Link
// 42 (original value)
api.startBatchEdit(); // Start Batch
api.startEditingCell({ rowIndex: 0, colKey: 'price' }); // Open editor
// getCellValue reads the live editor value
api.getCellValue({ rowNode, colKey: 'price', from: 'edit' }); // live editor value
api.getCellValue({ rowNode, colKey: 'price', from: 'data' }); // 42 (original data)
Writing Values Copy Link
rowNode.setDataValue() Copy Link
rowNode.setDataValue(colKey, newValue, eventSource?) writes a value programmatically. The eventSource parameter controls how.
eventSource | Active Editor | Pending Batch | Committed Data |
|---|---|---|---|
| (default) | Closed | Written | Written if no batch |
'edit' | Written | Written if no editor | Written if no editor, no batch |
'batch' | Left open | Written | Written if no batch |
'data' | Left open | — | Always written |
With 'edit', the active editor receives the new value via refresh() if implemented; otherwise the editor is recreated with focus preserved.
api.startBatchEdit(); // Start Batch
api.startEditingCell({ rowIndex: 0, colKey: 'price' }); // Open editor
rowNode.setDataValue('price', 99, 'edit'); // Update open editor without closing
api.getCellValue({ rowNode, colKey: 'price', from: 'edit' }); // 99 (live edit value)
rowNode.data.price; // 42 (unchanged)
api.stopEditing(); // Close editor
api.commitBatchEdit(); // Commit Batch
rowNode.getDataValue('price'); // 99 (committed)
api.startBatchEdit(); // Start Batch
rowNode.setDataValue('price', 99, 'batch'); // Update price
rowNode.setDataValue('qty', 5, 'batch'); // Update qty
rowNode.getDataValue('price'); // 42 (committed data)
rowNode.getDataValue('price', 'batch'); // 99 (pending)
api.commitBatchEdit(); // Commit Batch
rowNode.getDataValue('price'); // 99 (committed data)
api.startBatchEdit(); // Start Batch
rowNode.setDataValue('price', 99, 'data'); // 'data' — bypass batch, write immediately
rowNode.data.price; // 99 (already committed)
api.cancelBatchEdit(); // 'data' writes are permanent
Undo / Redo Copy Link
When Undo / Redo is enabled, a committed batch is treated as a single undo action. Calling undo after commitBatchEdit() reverts all changes from that batch at once — no extra API calls are needed.
If cancelBatchEdit() is called instead, the pending edits are discarded without touching the undo history. The undo stack remains unchanged, as though the batch never happened.
Full Row Batch Editing Copy Link
In Full Row Batch Editing, starting an edit in any cell opens all editors for the current row. When row editing is completed, only the changed cells are included in the pending batch edits.
Customisation Copy Link
Custom Renderers & Editors Copy Link
Implement refresh() in your custom cell renderers and editors to receive updated values during a batch. The params passed to refresh() include the latest pending value.
Styling Copy Link
Pending edit styles can be overridden using CSS, via the .ag-cell-batch-edit and .ag-row-batch-edit classes.
.ag-cell-batch-edit {
background-color: var(--ag-cell-batch-edit-background-color);
color: var(--ag-cell-batch-edit-text-color);
}
.ag-row-batch-edit {
background-color: var(--ag-row-batch-edit-background-color);
color: var(--ag-row-batch-edit-text-color);
}
The following example shows the custom batch styling:
- A batch is started automatically via
api.startBatchEdit() - Two rows have data updated via
rowNode.setDataValue() - Note how the styles are removed when the batch is committed or reverted
API Copy Link
Starts a batch editing session. While batch editing is active, cell edits are accumulated
as pending values without being committed to the row data. The pending values are only
written when commitBatchEdit() is called, or discarded when cancelBatchEdit() is called.
Calling startBatchEdit() while a batch is already active is a no-op.
Use isBatchEditing() to check whether a batch session is currently active.
Any active cell editor is cancelled when the batch session starts.
The batchEditingStarted event is fired lazily on the first actual cell edit within the
batch session, not when startBatchEdit() is called.
Only supported with the Client-Side Row Model. |
Commits all pending batch edits to the row data and ends the batch editing session.
Each accumulated pending value is written via rowNode.setDataValue(), and the
batchEditingStopped event is fired with the committed edits.
Calling commitBatchEdit() when no batch is active is a no-op.
If no cells were edited during the batch session (i.e. batchEditingStarted was never
fired), batchEditingStopped is not fired either.
Only supported with the Client-Side Row Model. |
Cancels all pending batch edits, reverting cells to their original values, and ends
the batch editing session. The batchEditingStopped event is fired with an empty edit map.
Calling cancelBatchEdit() when no batch is active is a no-op.
If no cells were edited during the batch session (i.e. batchEditingStarted was never
fired), batchEditingStopped is not fired either.
Only supported with the Client-Side Row Model. |
Returns true if a batch editing session is currently active (i.e. startBatchEdit()
has been called and neither commitBatchEdit() nor cancelBatchEdit() has been called yet). |
If the grid is editing, returns back details of the editing cell(s). |
If the grid is editing, returns back edit values of the row if any. |