---
product: "AG Grid"
title: "Columns Tool Panel - Deferred Updates"
description: "Add Apply, Cancel and Reset buttons to the Columns Tool Panel, and stage changes until the user applies them."
enterprise: true
framework: angular
version: "36.3.0"
related:
    - title: "Configuration"
      url: "https://www.ag-grid.com/angular-data-grid/tool-panel-columns-configuration/"
    - title: "Customisation"
      url: "https://www.ag-grid.com/angular-data-grid/tool-panel-columns-customising/"
llms: "https://www.ag-grid.com/llms.txt"
---

# Columns Tool Panel - Deferred Updates

Add Apply, Cancel and Reset buttons to the Columns Tool Panel, and stage changes until the user applies them.

## Deferred Updates

Deferred Updates stage changes made in the Columns Tool Panel until the user clicks **Apply**. Users can make several configuration changes and apply them in a single update, avoiding intermediate recomputations or server requests.

The example below demonstrates Deferred Updates. Note the following:

- Changes made in the Columns Tool Panel are staged as pending changes.
- **Apply** commits all pending changes in a single operation.
- **Cancel** discards all pending changes and restores the last applied state.
- **Reset** immediately restores the columns to the state defined in the current column definitions and discards all pending changes.

#### Deferred Updates

```ts
import { Component } from "@angular/core";
import { HttpClient } from "@angular/common/http";
import { AgGridAngular } from "ag-grid-angular";
import {
  AutoGroupColumnDef,
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  GridApi,
  GridOptions,
  GridReadyEvent,
  ModuleRegistry,
  SideBarDef,
  enableDevValidations,
} from "ag-grid-community";
import {
  ColumnMenuModule,
  ColumnsToolPanelModule,
  ContextMenuModule,
  PivotModule,
  RowGroupingPanelModule,
} from "ag-grid-enterprise";
import "./styles.css";

if (process.env.NODE_ENV !== "production") {
  // Enable extended validations only for development
  enableDevValidations();
}

ModuleRegistry.registerModules([
  ClientSideRowModelModule,
  ColumnsToolPanelModule,
  ColumnMenuModule,
  ContextMenuModule,
  PivotModule,
  RowGroupingPanelModule,
]);
import { IOlympicData } from "./interfaces";

@Component({
  selector: "my-app",
  standalone: true,
  imports: [AgGridAngular],
  template: `<div class="example-wrapper">
    <ag-grid-angular
      style="width: 100%; height: 100%;"
      [columnDefs]="columnDefs"
      [defaultColDef]="defaultColDef"
      [autoGroupColumnDef]="autoGroupColumnDef"
      [rowGroupPanelShow]="rowGroupPanelShow"
      [pivotPanelShow]="pivotPanelShow"
      [sideBar]="sideBar"
      [rowData]="rowData"
      (gridReady)="onGridReady($event)"
    />
  </div> `,
})
export class AppComponent {
  columnDefs: ColDef[] = [
    {
      field: "athlete",
      minWidth: 200,
      enableRowGroup: true,
      enablePivot: true,
    },
    { field: "age", enableValue: true },
    {
      field: "country",
      minWidth: 200,
      enableRowGroup: true,
      enablePivot: true,
      rowGroup: true,
    },
    { field: "year", enableRowGroup: true, enablePivot: true },
    { field: "date", minWidth: 180, enableRowGroup: true, enablePivot: true },
    { field: "sport", minWidth: 200, enableRowGroup: true, enablePivot: true },
    { field: "gold", hide: true, enableValue: true },
    { field: "silver", hide: true, enableValue: true, aggFunc: "sum" },
    { field: "bronze", hide: true, enableValue: true, aggFunc: "sum" },
    { headerName: "Total", field: "total", enableValue: true },
  ];
  defaultColDef: ColDef = {
    flex: 1,
    minWidth: 150,
  };
  autoGroupColumnDef: AutoGroupColumnDef = {
    minWidth: 250,
  };
  rowGroupPanelShow: "always" | "onlyWhenGrouping" | "never" = "always";
  pivotPanelShow: "always" | "onlyWhenPivoting" | "never" = "always";
  sideBar: SideBarDef | string | string[] | boolean | null = {
    toolPanels: [
      {
        id: "columns",
        labelDefault: "Columns",
        labelKey: "columns",
        iconKey: "columns",
        toolPanel: "agColumnsToolPanel",
        width: 300,
        toolPanelParams: {
          buttons: ["reset", "cancel", "apply"],
        },
      },
    ],
    defaultToolPanel: "columns",
  };
  rowData!: IOlympicData[];

  constructor(private http: HttpClient) {}

  onGridReady(params: GridReadyEvent<IOlympicData>) {
    this.http
      .get<IOlympicData[]>(
        "https://www.ag-grid.com/example-assets/olympic-winners.json",
      )
      .subscribe((data) => (this.rowData = data));
  }
}
```

[Live example: Deferred Updates](https://www.ag-grid.com/examples/tool-panel-columns-deferred-updates/deferred-apply-mode-csrm/angular/)

Include `'apply'` in `toolPanelParams.buttons` to enable Deferred Updates:

```ts
<ag-grid-angular
    [sideBar]="sideBar"
    /* other grid options ... */ />

this.sideBar = {
    toolPanels: [
        {
            id: 'columns',
            labelDefault: 'Columns',
            labelKey: 'columns',
            iconKey: 'columns',
            toolPanel: 'agColumnsToolPanel',
            toolPanelParams: {
                buttons: ['cancel', 'apply'],
            },
        },
    ],
    defaultToolPanel: 'columns',
};
```

> **Note**
>
> Changes made outside the Columns Tool Panel, such as dragging columns into the Row Group or Pivot Panels, using the Column Menu, or calling the Grid API, are applied immediately and clear any pending changes. Column pinning, resizing and group expansion do not clear pending changes.

## Reset Without Deferred Updates

The **Reset** button does not depend on Deferred Updates. Include `'reset'` without `'apply'` to add a button that resets the columns to the state defined in the current column definitions, as [`api.resetColumnState()`](https://www.ag-grid.com/angular-data-grid/column-state/#reference-state-resetColumnState) does.

The example below adds only a **Reset** button. Note the following:

- Changes made in the Columns Tool Panel are applied immediately, as there is no **Apply** button.
- **Reset** restores the columns to the state defined in the current column definitions.

#### Reset Button

```ts
import { Component } from "@angular/core";
import { HttpClient } from "@angular/common/http";
import { AgGridAngular } from "ag-grid-angular";
import {
  AutoGroupColumnDef,
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  GridApi,
  GridOptions,
  GridReadyEvent,
  ModuleRegistry,
  SideBarDef,
  enableDevValidations,
} from "ag-grid-community";
import {
  ColumnMenuModule,
  ColumnsToolPanelModule,
  ContextMenuModule,
  RowGroupingModule,
} from "ag-grid-enterprise";
import "./styles.css";

if (process.env.NODE_ENV !== "production") {
  // Enable extended validations only for development
  enableDevValidations();
}

ModuleRegistry.registerModules([
  ClientSideRowModelModule,
  ColumnsToolPanelModule,
  ColumnMenuModule,
  ContextMenuModule,
  RowGroupingModule,
]);
import { IOlympicData } from "./interfaces";

@Component({
  selector: "my-app",
  standalone: true,
  imports: [AgGridAngular],
  template: `<div class="example-wrapper">
    <ag-grid-angular
      style="width: 100%; height: 100%;"
      [columnDefs]="columnDefs"
      [defaultColDef]="defaultColDef"
      [autoGroupColumnDef]="autoGroupColumnDef"
      [sideBar]="sideBar"
      [rowData]="rowData"
      (gridReady)="onGridReady($event)"
    />
  </div> `,
})
export class AppComponent {
  columnDefs: ColDef[] = [
    { field: "athlete", minWidth: 200 },
    { field: "age", enableValue: true },
    { field: "country", minWidth: 200, enableRowGroup: true, rowGroup: true },
    { field: "year", enableRowGroup: true },
    { field: "sport", minWidth: 200, enableRowGroup: true },
    { field: "gold", hide: true, enableValue: true },
    { field: "silver", hide: true, enableValue: true },
    { field: "bronze", hide: true, enableValue: true },
    { headerName: "Total", field: "total", enableValue: true },
  ];
  defaultColDef: ColDef = {
    flex: 1,
    minWidth: 150,
  };
  autoGroupColumnDef: AutoGroupColumnDef = {
    minWidth: 250,
  };
  sideBar: SideBarDef | string | string[] | boolean | null = {
    toolPanels: [
      {
        id: "columns",
        labelDefault: "Columns",
        labelKey: "columns",
        iconKey: "columns",
        toolPanel: "agColumnsToolPanel",
        toolPanelParams: {
          buttons: ["reset"],
        },
      },
    ],
    defaultToolPanel: "columns",
  };
  rowData!: IOlympicData[];

  constructor(private http: HttpClient) {}

  onGridReady(params: GridReadyEvent<IOlympicData>) {
    this.http
      .get<IOlympicData[]>(
        "https://www.ag-grid.com/example-assets/olympic-winners.json",
      )
      .subscribe((data) => (this.rowData = data));
  }
}
```

[Live example: Reset Button](https://www.ag-grid.com/examples/tool-panel-columns-deferred-updates/reset-button/angular/)

## Server-Side Row Model

With the [Server-Side Row Model](https://www.ag-grid.com/angular-data-grid/server-side-model/), Deferred Updates batch several configuration changes into a single server request. See [Deferred Column Configuration](https://www.ag-grid.com/angular-data-grid/server-side-model-grouping/#deferred-column-configuration) for an example.

## API

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `buttons` | `ColumnToolPanelAction[]` |  |  | Buttons to display at the bottom of the Columns Tool Panel, in the order they should be displayed in. `'apply'`: Changes are deferred until the Apply button is clicked. `'cancel'`: Discards any deferred changes. Only has an effect when `'apply'` is also included. `'reset'`: Immediately resets the columns to the state defined in the current column definitions, discarding any pending changes. Only the `'apply'` button enables deferred changes. |
