---
title: "Batch Editing"
enterprise: true
framework: vue
version: "36.1.0"
---

# Batch Editing

Batch editing lets you queue edits across multiple cells or rows, then commit or discard them all at once.

## Enabling Batch Editing

1. **Start** — call `api.startBatchEdit()` to start a batch edit.
2. **Edit** — make one or more edits. Pending values are displayed in the grid but not written to the data.
3. **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 call `api.cancelBatchEdit()`.

> **Note**
>
> Batch editing is only available via the API and only compatible with the [Client-Side Row Model](https://www.ag-grid.com/vue-data-grid/row-models/).

#### Batch Editing API

```ts
import {
  createApp,
  defineComponent,
  onBeforeMount,
  ref,
  shallowRef,
} from "vue";
import { AgGridVue } from "ag-grid-vue3";
import "./styles.css";
import {
  CellEditingStartedEvent,
  CellEditingStoppedEvent,
  CellValueChangedEvent,
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  GridApi,
  GridOptions,
  GridReadyEvent,
  ModuleRegistry,
  NumberEditorModule,
  RowEditingStartedEvent,
  RowEditingStoppedEvent,
  TextEditorModule,
  ValueGetterParams,
  enableDevValidations,
} from "ag-grid-community";
import {
  BatchEditModule,
  CellSelectionModule,
  ClipboardModule,
  RowGroupingModule,
} from "ag-grid-enterprise";
if (process.env.NODE_ENV !== "production") {
  enableDevValidations();
}

ModuleRegistry.registerModules([
  NumberEditorModule,
  CellSelectionModule,
  TextEditorModule,
  ClientSideRowModelModule,
  BatchEditModule,
  ClipboardModule,
  RowGroupingModule,
]);

function sumTotalValueGetter(params: ValueGetterParams): number {
  const { node, data, api } = params;
  const overlay = node ? api.getEditRowValues(node) : undefined;
  const row = Object.assign({}, data, overlay);
  return (row.gold ?? 0) + (row.silver ?? 0) + (row.bronze ?? 0);
}

const VueExample = defineComponent({
  template: `
        <div style="height: 100%">
                <div class="example-wrapper">
      <div class="example-buttons">
        <div class="example-button-row">
          <button v-on:click="startBatchEdit()">Start Batch</button>
          <button v-on:click="commitBatchEdit()">Commit Batch</button>
          <button v-on:click="cancelBatchEdit()">Cancel Batch</button>
          <button v-on:click="getEditingCells()">Get Editing Cells</button>
          <div>Batch Mode: <span id="batchStatusValue">Inactive</span></div>
        </div>
      </div>
      <div class="grid-wrapper">
        <ag-grid-vue
          style="width: 100%; height: 100%;"
          @grid-ready="onGridReady"
          :columnDefs="columnDefs"
          :defaultColDef="defaultColDef"
          :grandTotalRow="grandTotalRow"
          :rowData="rowData"
          @row-editing-started="onRowEditingStarted"
          @row-editing-stopped="onRowEditingStopped"
          @cell-editing-started="onCellEditingStarted"
          @cell-editing-stopped="onCellEditingStopped"
          @cell-value-changed="onCellValueChanged"></ag-grid-vue>
        </div>
      </div>
        </div>
    `,
  components: {
    "ag-grid-vue": AgGridVue,
  },
  setup(props) {
    const gridApi = shallowRef<GridApi | null>(null);
    const columnDefs = ref<ColDef[]>([
      { field: "athlete", minWidth: 120 },
      { field: "age", aggFunc: "avg" },
      { field: "country" },
      { field: "date" },
      { field: "sport", minWidth: 120 },
      { field: "gold" },
      { field: "silver" },
      { field: "bronze", minWidth: 100 },
      {
        field: "total",
        aggFunc: "sum",
        valueGetter: sumTotalValueGetter,
        editable: false,
      },
    ]);
    const defaultColDef = ref<ColDef>({
      flex: 1,
      editable: true,
    });
    const grandTotalRow = ref<"top" | "bottom" | "pinnedTop" | "pinnedBottom">(
      "bottom",
    );
    const rowData = ref<any[]>(null);

    function onRowEditingStarted(_event: RowEditingStartedEvent) {
      console.log("rowEditingStarted");
    }
    function onRowEditingStopped(_event: RowEditingStoppedEvent) {
      console.log("rowEditingStopped");
    }
    function onCellEditingStarted(_event: CellEditingStartedEvent) {
      console.log("cellEditingStarted");
    }
    function onCellEditingStopped(_event: CellEditingStoppedEvent) {
      console.log("cellEditingStopped");
    }
    function onCellValueChanged(_event: CellValueChangedEvent) {
      console.log("Cell value changed");
    }
    function getEditingCells() {
      const cells = gridApi.value!.getEditingCells();
      console.log("Editing cells:", cells);
    }
    function startBatchEdit() {
      gridApi.value!.startBatchEdit();
      const el = document.querySelector<HTMLElement>("#batchStatusValue");
      if (el) el.textContent = "Active";
    }
    function commitBatchEdit() {
      gridApi.value!.commitBatchEdit();
      const el = document.querySelector<HTMLElement>("#batchStatusValue");
      if (el) el.textContent = "Inactive";
    }
    function cancelBatchEdit() {
      gridApi.value!.cancelBatchEdit();
      const el = document.querySelector<HTMLElement>("#batchStatusValue");
      if (el) el.textContent = "Inactive";
    }
    const onGridReady = (params: GridReadyEvent) => {
      gridApi.value = params.api;

      const updateData = (data) => (rowData.value = data);

      fetch("https://www.ag-grid.com/example-assets/small-olympic-winners.json")
        .then((resp) => resp.json())
        .then((data) => updateData(data));
    };

    return {
      gridApi,
      columnDefs,
      defaultColDef,
      grandTotalRow,
      rowData,
      onGridReady,
      onRowEditingStarted,
      onRowEditingStopped,
      onCellEditingStarted,
      onCellEditingStopped,
      onCellValueChanged,
      getEditingCells,
      startBatchEdit,
      commitBatchEdit,
      cancelBatchEdit,
    };
  },
});

const app = createApp(VueExample);
app.mount("#app");
```

[Live example: Batch Editing API](https://www.ag-grid.com/examples/cell-editing-batch/batch-editing-api/vue3)

## Batch Editing Lifecycle

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:

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `batchEditingStarted` | `BatchEditingStartedEvent` |  |  | 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. |
| `batchEditingStopped` | `BatchEditingStoppedEvent` |  |  | Batch editing has stopped (when batch editing is enabled). Contains a list of edits if the batch was committed via `api.commitBatchEdit()`. |

### Pending Values

Edits made during a batch are stored as **pending values** — they are not applied to the data until committed.

- **Display features** (cell rendering, tooltips, 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

There are two main APIs to read cell values but they differ in their default behaviour.

- **`rowNode.getDataValue()`** — defaults to `from: 'data'` (ignores pending edits). Use for data-facing reads.
- **`api.getCellValue()`** — defaults to `from: 'edit'` (shows pending edits). Use for UI-facing reads.

### rowNode.getDataValue()

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `getDataValue` | `Function` |  |  | 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, including `'transformed'` to read the displayed [Show Values As](https://www.ag-grid.com/vue-data-grid/aggregation-show-values-as/) value. |

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 |
| `'transformed'` | Editor value, transformed | Pending value, transformed | Transformed agg value | Fallback, transformed |

**Aggregate Values**

- **`'value'`** — same as `'data'`, but unwraps the aggregation result returned by `avg` and `count` to 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 typically `undefined` since group rows do not hold leaf data.
- **`'transformed'`** — same source precedence as `'edit'`, then applies the displayed [Show Values As](https://www.ag-grid.com/vue-data-grid/aggregation-show-values-as/) value (e.g. a percentage of a total). Falls back to the raw edit-aware value when the column has no Show Values As mode.

**Formula Cells (`allowFormula: true`)**

- **`'data'` / `'value'`** — return the computed result.
- **`'edit'` / `'batch'` / `'data-raw'`** — return the raw formula string (e.g. `"=A1*2"`).
- **`'transformed'`** — resolves the computed result, then applies Show Values As.

### Example getDataValue()

```js
                                             // 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)
```

```js
// 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()

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `getCellValue` | `Function` |  |  | 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`. The `params.from` option controls which value is resolved, including `'transformed'` to read the displayed [Show Values As](https://www.ag-grid.com/vue-data-grid/aggregation-show-values-as/) value. Module: [`CellApiModule`](https://www.ag-grid.com/vue-data-grid/modules/). |

| `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 |
| `'transformed'` | Editor value, transformed | Pending value, transformed | Transformed agg value | Fallback, transformed |

`'transformed'` uses the same edit-aware source precedence as `'edit'`, then applies the displayed [Show Values As](https://www.ag-grid.com/vue-data-grid/aggregation-show-values-as/) value. It falls back to the raw edit-aware value when the column has no such mode. The other options return the raw value, unaffected by Show Values As.

### Example getCellValue()

```js
                                                              // 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

### rowNode.setDataValue()

`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.

```js
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)
```

```js
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)
```

```js
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

When [Undo / Redo](https://www.ag-grid.com/vue-data-grid/undo-redo-edits/) 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

In [Full Row](https://www.ag-grid.com/vue-data-grid/cell-editing-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.

#### Batch Editing FullRow

```ts
import {
  createApp,
  defineComponent,
  onBeforeMount,
  ref,
  shallowRef,
} from "vue";
import { AgGridVue } from "ag-grid-vue3";
import "./styles.css";
import {
  CellEditingStartedEvent,
  CellEditingStoppedEvent,
  CellValueChangedEvent,
  CheckboxEditorModule,
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  EditStrategyType,
  GridApi,
  GridOptions,
  GridReadyEvent,
  ModuleRegistry,
  NumberEditorModule,
  RowEditingStartedEvent,
  RowEditingStoppedEvent,
  TextEditorModule,
  enableDevValidations,
} from "ag-grid-community";
import {
  BatchEditModule,
  CellSelectionModule,
  ClipboardModule,
} from "ag-grid-enterprise";
import { getData } from "./data";
if (process.env.NODE_ENV !== "production") {
  enableDevValidations();
}

ModuleRegistry.registerModules([
  NumberEditorModule,
  CellSelectionModule,
  TextEditorModule,
  ClientSideRowModelModule,
  CheckboxEditorModule,
  BatchEditModule,
  ClipboardModule,
]);

const VueExample = defineComponent({
  template: `
        <div style="height: 100%">
                <div class="example-wrapper">
      <div class="example-buttons">
        <div class="example-button-row">
          <button v-on:click="startBatchEdit()">Start Batch</button>
          <button v-on:click="commitBatchEdit()">Commit Batch</button>
          <button v-on:click="cancelBatchEdit()">Cancel Batch</button>
          <button v-on:click="getEditingCells()">Get Editing Cells</button>
          <div>Batch Mode: <span id="batchStatusValue">Inactive</span></div>
        </div>
      </div>
      <div class="grid-wrapper">
        <ag-grid-vue
          style="width: 100%; height: 100%;"
          @grid-ready="onGridReady"
          :columnDefs="columnDefs"
          :defaultColDef="defaultColDef"
          :rowData="rowData"
          :editType="editType"
          @row-editing-started="onRowEditingStarted"
          @row-editing-stopped="onRowEditingStopped"
          @cell-editing-started="onCellEditingStarted"
          @cell-editing-stopped="onCellEditingStopped"
          @cell-value-changed="onCellValueChanged"></ag-grid-vue>
        </div>
      </div>
        </div>
    `,
  components: {
    "ag-grid-vue": AgGridVue,
  },
  setup(props) {
    const gridApi = shallowRef<GridApi | null>(null);
    const columnDefs = ref<ColDef[]>([
      { field: "firstName" },
      { field: "lastName" },
      { field: "gender" },
      { field: "age" },
      { field: "mood" },
      { field: "country", editable: false },
      { field: "address", minWidth: 200 },
    ]);
    const defaultColDef = ref<ColDef>({
      flex: 1,
      editable: true,
    });
    const rowData = ref<any[] | null>(getData());
    const editType = ref<EditStrategyType>("fullRow");

    function onRowEditingStarted(_event: RowEditingStartedEvent) {
      console.log("rowEditingStarted");
    }
    function onRowEditingStopped(_event: RowEditingStoppedEvent) {
      console.log("rowEditingStopped");
    }
    function onCellEditingStarted(_event: CellEditingStartedEvent) {
      console.log("cellEditingStarted");
    }
    function onCellEditingStopped(_event: CellEditingStoppedEvent) {
      console.log("cellEditingStopped");
    }
    function onCellValueChanged(_event: CellValueChangedEvent) {
      console.log("Cell value changed");
    }
    function getEditingCells() {
      const cells = gridApi.value!.getEditingCells();
      console.log("Editing cells:", cells);
    }
    function startBatchEdit() {
      gridApi.value!.startBatchEdit();
      const el = document.querySelector<HTMLElement>("#batchStatusValue");
      if (el) el.textContent = "Active";
    }
    function commitBatchEdit() {
      gridApi.value!.commitBatchEdit();
      const el = document.querySelector<HTMLElement>("#batchStatusValue");
      if (el) el.textContent = "Inactive";
    }
    function cancelBatchEdit() {
      gridApi.value!.cancelBatchEdit();
      const el = document.querySelector<HTMLElement>("#batchStatusValue");
      if (el) el.textContent = "Inactive";
    }
    const onGridReady = (params: GridReadyEvent) => {
      gridApi.value = params.api;
    };

    return {
      gridApi,
      columnDefs,
      defaultColDef,
      rowData,
      editType,
      onGridReady,
      onRowEditingStarted,
      onRowEditingStopped,
      onCellEditingStarted,
      onCellEditingStopped,
      onCellValueChanged,
      getEditingCells,
      startBatchEdit,
      commitBatchEdit,
      cancelBatchEdit,
    };
  },
});

const app = createApp(VueExample);
app.mount("#app");
```

[Live example: Batch Editing FullRow](https://www.ag-grid.com/examples/cell-editing-batch/batch-editing-fullrow/vue3)

## Customisation

### Custom Renderers & Editors

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.

#### Batch Editing Customization

```ts
import {
  createApp,
  defineComponent,
  onBeforeMount,
  ref,
  shallowRef,
} from "vue";
import { AgGridVue } from "ag-grid-vue3";
import "./styles.css";
import {
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  CustomEditorModule,
  GridApi,
  GridOptions,
  GridReadyEvent,
  ModuleRegistry,
  NumberEditorModule,
  TextEditorModule,
  enableDevValidations,
} from "ag-grid-community";
import {
  BatchEditModule,
  ClipboardModule,
  RichSelectModule,
} from "ag-grid-enterprise";
import GenderRenderer from "./genderRendererVue";
import MoodEditor from "./moodEditorVue";
import MoodRenderer from "./moodRendererVue";
import SimpleTextEditor from "./simpleTextEditorVue";
import { getData } from "./data";
if (process.env.NODE_ENV !== "production") {
  enableDevValidations();
}

ModuleRegistry.registerModules([
  ClientSideRowModelModule,
  RichSelectModule,
  BatchEditModule,
  ClipboardModule,
  NumberEditorModule,
  TextEditorModule,
  CustomEditorModule,
]);

const VueExample = defineComponent({
  template: `
        <div style="height: 100%">
                <div class="example-wrapper">
      <div class="example-buttons">
        <div class="example-button-row">
          <button v-on:click="startBatchEdit()">Start Batch</button>
          <button v-on:click="commitBatchEdit()">Commit Batch</button>
          <button v-on:click="cancelBatchEdit()">Cancel Batch</button>
          <button v-on:click="getEditingCells()">Get Editing Cells</button>
          <div>Batch Mode: <span id="batchStatusValue">Inactive</span></div>
        </div>
      </div>
      <div class="grid-wrapper">
        <ag-grid-vue
          style="width: 100%; height: 100%;"
          @grid-ready="onGridReady"
          :columnDefs="columnDefs"
          :rowData="rowData"
          :defaultColDef="defaultColDef"></ag-grid-vue>
        </div>
      </div>
        </div>
    `,
  components: {
    "ag-grid-vue": AgGridVue,
    GenderRenderer,
    MoodEditor,
    MoodRenderer,
    SimpleTextEditor,
  },
  setup(props) {
    const gridApi = shallowRef<GridApi | null>(null);
    const columnDefs = ref<ColDef[]>([
      { field: "first_name", headerName: "Provided Text" },
      {
        field: "last_name",
        headerName: "Custom Text",
        cellEditor: "SimpleTextEditor",
      },
      {
        field: "age",
        headerName: "Provided Number",
        cellEditor: "agNumberCellEditor",
      },
      {
        field: "gender",
        headerName: "Provided Rich Select",
        cellRenderer: "GenderRenderer",
        cellEditor: "agRichSelectCellEditor",
        cellEditorParams: {
          cellRenderer: "GenderRenderer",
          values: ["Male", "Female"],
        },
      },
      {
        field: "mood",
        headerName: "Custom Mood",
        cellRenderer: "MoodRenderer",
        cellEditor: "MoodEditor",
        cellEditorPopup: true,
      },
    ]);
    const rowData = ref<any[] | null>(getData());
    const defaultColDef = ref<ColDef>({
      editable: true,
      flex: 1,
      minWidth: 100,
    });

    function getEditingCells() {
      const cells = gridApi.value!.getEditingCells();
      console.log("Editing cells:", cells);
    }
    function startBatchEdit() {
      gridApi.value!.startBatchEdit();
      const el = document.querySelector<HTMLElement>("#batchStatusValue");
      if (el) el.textContent = "Active";
    }
    function commitBatchEdit() {
      gridApi.value!.commitBatchEdit();
      const el = document.querySelector<HTMLElement>("#batchStatusValue");
      if (el) el.textContent = "Inactive";
    }
    function cancelBatchEdit() {
      gridApi.value!.cancelBatchEdit();
      const el = document.querySelector<HTMLElement>("#batchStatusValue");
      if (el) el.textContent = "Inactive";
    }
    const onGridReady = (params: GridReadyEvent) => {
      gridApi.value = params.api;
    };

    return {
      gridApi,
      columnDefs,
      rowData,
      defaultColDef,
      onGridReady,
      getEditingCells,
      startBatchEdit,
      commitBatchEdit,
      cancelBatchEdit,
    };
  },
});

const app = createApp(VueExample);
app.mount("#app");
```

[Live example: Batch Editing Customization](https://www.ag-grid.com/examples/cell-editing-batch/batch-editing-custom/vue3)

### Styling

Pending edit styles can be overridden using CSS, via the `.ag-cell-batch-edit` and `.ag-row-batch-edit` classes.

```scss
.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

#### Batch Editing Styles

```ts
import {
  createApp,
  defineComponent,
  onBeforeMount,
  ref,
  shallowRef,
} from "vue";
import { AgGridVue } from "ag-grid-vue3";
import "./styles.css";
import {
  CellEditingStartedEvent,
  CellEditingStoppedEvent,
  CellValueChangedEvent,
  CheckboxEditorModule,
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  EditStrategyType,
  GridApi,
  GridOptions,
  GridReadyEvent,
  ModuleRegistry,
  NumberEditorModule,
  RowApiModule,
  RowEditingStartedEvent,
  RowEditingStoppedEvent,
  TextEditorModule,
  enableDevValidations,
} from "ag-grid-community";
import {
  BatchEditModule,
  CellSelectionModule,
  ClipboardModule,
} from "ag-grid-enterprise";
import { getData } from "./data";
if (process.env.NODE_ENV !== "production") {
  enableDevValidations();
}

ModuleRegistry.registerModules([
  NumberEditorModule,
  CellSelectionModule,
  TextEditorModule,
  ClientSideRowModelModule,
  RowApiModule,
  CheckboxEditorModule,
  BatchEditModule,
  ClipboardModule,
]);

const VueExample = defineComponent({
  template: `
        <div style="height: 100%">
                <div class="example-wrapper">
      <div class="example-buttons">
        <div class="example-button-row">
          <button v-on:click="startBatchEdit()">Start Batch</button>
          <button v-on:click="commitBatchEdit()">Commit Batch</button>
          <button v-on:click="cancelBatchEdit()">Cancel Batch</button>
          <button v-on:click="getEditingCells()">Get Editing Cells</button>
          <div>Batch Mode: <span id="batchStatusValue">Inactive</span></div>
        </div>
      </div>
      <div class="grid-wrapper">
        <ag-grid-vue
          style="width: 100%; height: 100%;"
          @grid-ready="onGridReady"
          :columnDefs="columnDefs"
          :defaultColDef="defaultColDef"
          :rowData="rowData"
          :editType="editType"
          @row-editing-started="onRowEditingStarted"
          @row-editing-stopped="onRowEditingStopped"
          @cell-editing-started="onCellEditingStarted"
          @cell-editing-stopped="onCellEditingStopped"
          @cell-value-changed="onCellValueChanged"
          @first-data-rendered="onFirstDataRendered"></ag-grid-vue>
        </div>
      </div>
        </div>
    `,
  components: {
    "ag-grid-vue": AgGridVue,
  },
  setup(props) {
    const gridApi = shallowRef<GridApi | null>(null);
    const columnDefs = ref<ColDef[]>([
      { field: "firstName" },
      { field: "lastName" },
      { field: "gender" },
      { field: "age" },
      { field: "mood" },
      { field: "country", editable: false },
      { field: "address", minWidth: 200 },
    ]);
    const defaultColDef = ref<ColDef>({
      flex: 1,
      editable: true,
    });
    const rowData = ref<any[] | null>(getData());
    const editType = ref<EditStrategyType>("fullRow");

    function onRowEditingStarted(_event: RowEditingStartedEvent) {
      console.log("rowEditingStarted");
    }
    function onRowEditingStopped(_event: RowEditingStoppedEvent) {
      console.log("rowEditingStopped");
    }
    function onCellEditingStarted(_event: CellEditingStartedEvent) {
      console.log("cellEditingStarted");
    }
    function onCellEditingStopped(_event: CellEditingStoppedEvent) {
      console.log("cellEditingStopped");
    }
    function onCellValueChanged(_event: CellValueChangedEvent) {
      console.log("Cell value changed");
    }
    function onFirstDataRendered(params) {
      gridApi.value = params.api;
      gridApi.value.startBatchEdit();
      gridApi.value
        .getDisplayedRowAtIndex(0)
        ?.setDataValue("firstName", "Justine");
      gridApi.value.getDisplayedRowAtIndex(1)?.setDataValue("age", 101);
      const el = document.querySelector<HTMLElement>("#batchStatusValue");
      if (el) el.textContent = "Active";
    }
    function getEditingCells() {
      const cells = gridApi.value!.getEditingCells();
      console.log("Editing cells:", cells);
    }
    function startBatchEdit() {
      gridApi.value!.startBatchEdit();
      const el = document.querySelector<HTMLElement>("#batchStatusValue");
      if (el) el.textContent = "Active";
    }
    function commitBatchEdit() {
      gridApi.value!.commitBatchEdit();
      const el = document.querySelector<HTMLElement>("#batchStatusValue");
      if (el) el.textContent = "Inactive";
    }
    function cancelBatchEdit() {
      gridApi.value!.cancelBatchEdit();
      const el = document.querySelector<HTMLElement>("#batchStatusValue");
      if (el) el.textContent = "Inactive";
    }
    const onGridReady = (params: GridReadyEvent) => {
      gridApi.value = params.api;
    };

    return {
      gridApi,
      columnDefs,
      defaultColDef,
      rowData,
      editType,
      onGridReady,
      onRowEditingStarted,
      onRowEditingStopped,
      onCellEditingStarted,
      onCellEditingStopped,
      onCellValueChanged,
      onFirstDataRendered,
      getEditingCells,
      startBatchEdit,
      commitBatchEdit,
      cancelBatchEdit,
    };
  },
});

const app = createApp(VueExample);
app.mount("#app");
```

[Live example: Batch Editing Styles](https://www.ag-grid.com/examples/cell-editing-batch/batch-editing-styles/vue3)

## API

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `startBatchEdit` | `Function` |  |  | 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. Module: [`BatchEditModule`](https://www.ag-grid.com/vue-data-grid/modules/). |
| `commitBatchEdit` | `Function` |  |  | 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. With `invalidEditValueMode: 'block'`, a commit is rejected while any edit is invalid: nothing is written, `batchEditingStopped` does not fire, and the batch and its editors stay open so the value can be corrected and the commit retried (or `cancelBatchEdit()` called). Only supported with the Client-Side Row Model. Module: [`BatchEditModule`](https://www.ag-grid.com/vue-data-grid/modules/). |
| `cancelBatchEdit` | `Function` |  |  | 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. Module: [`BatchEditModule`](https://www.ag-grid.com/vue-data-grid/modules/). |
| `isBatchEditing` | `Function` |  |  | 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). Module: [`BatchEditModule`](https://www.ag-grid.com/vue-data-grid/modules/). |

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `getEditingCells` | `Function` |  |  | If the grid is editing, returns back details of the editing cell(s). Modules (any of): [`TextEditorModule`](https://www.ag-grid.com/vue-data-grid/modules/), [`LargeTextEditorModule`](https://www.ag-grid.com/vue-data-grid/modules/), [`NumberEditorModule`](https://www.ag-grid.com/vue-data-grid/modules/), [`DateEditorModule`](https://www.ag-grid.com/vue-data-grid/modules/), [`CheckboxEditorModule`](https://www.ag-grid.com/vue-data-grid/modules/), [`CustomEditorModule`](https://www.ag-grid.com/vue-data-grid/modules/), [`SelectEditorModule`](https://www.ag-grid.com/vue-data-grid/modules/), [`RichSelectModule`](https://www.ag-grid.com/vue-data-grid/modules/). |
| `getEditRowValues` | `Function` |  |  | If the grid is editing, returns back edit values of the row if any. Modules (any of): [`TextEditorModule`](https://www.ag-grid.com/vue-data-grid/modules/), [`LargeTextEditorModule`](https://www.ag-grid.com/vue-data-grid/modules/), [`NumberEditorModule`](https://www.ag-grid.com/vue-data-grid/modules/), [`DateEditorModule`](https://www.ag-grid.com/vue-data-grid/modules/), [`CheckboxEditorModule`](https://www.ag-grid.com/vue-data-grid/modules/), [`CustomEditorModule`](https://www.ag-grid.com/vue-data-grid/modules/), [`SelectEditorModule`](https://www.ag-grid.com/vue-data-grid/modules/), [`RichSelectModule`](https://www.ag-grid.com/vue-data-grid/modules/). |
