---
title: "Column State"
framework: angular
version: "36.1.0"
---

# Column State

Column Definitions contain both stateful and non-stateful attributes. Stateful attributes can have their values changed by the grid (e.g. Column sort can be changed by the user clicking on the column header). Non-stateful attributes do not change from what is set in the Column Definition (e.g. once the Field is set as part of a Column Definition, it does not change).

> **Note**
>
> The DOM also has stateful vs non-stateful attributes. For example consider a DOM element and setting `element.style.width="100px"` will indefinitely set width to 100 pixels, the browser will not change this value. However setting `element.scrollTop=200` will set the scroll position, but the browser can change the scroll position further following user interaction, thus scroll position is stateful as the browser can change the state.

The full list of stateful attributes of Columns are represented by the `ColumnStateParams` interface:

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `hide` | `boolean \| null` |  |  | True if the column is hidden |
| `width` | `number \| null` |  |  | Width of the column in pixels |
| `flex` | `number \| null` |  |  | Column's flex if flex is set |
| `sort` | `SortDirection` |  |  | The sort direction of the column |
| `sortType` | `SortType \| null` |  |  | The type of sort applied to the column |
| `sortIndex` | `number \| null` |  |  | The order of the sort, if sorting by many columns |
| `aggFunc` | [`string \| IAggFunc \| null`](https://www.ag-grid.com/angular-data-grid/aggregation-custom-functions/) |  |  | The aggregation function applied |
| `valueIndex` | `number \| null` |  |  | The position of this column in the order of value columns when aggregating in pivot mode. When aggregating by a single column, any number can be used. When aggregating by multiple columns, this determines the order (e.g. `0` for first, `1` for second). |
| `pivot` | `boolean \| null` |  |  | True if pivot active |
| `pivotIndex` | `number \| null` |  |  | The order of the pivot, if pivoting by many columns |
| `pivotSort` | `SortDirection` |  |  | The sort direction applied to this column's pivot result columns. Isolated from `sort`. |
| `pinned` | `ColumnPinnedType` |  |  | Set if column is pinned |
| `rowGroup` | `boolean \| null` |  |  | True if row group active |
| `rowGroupIndex` | `number \| null` |  |  | The order of the row group, if grouping by many columns |
| `showValuesAs` | `ShowValuesAsStateValue` |  |  | The active "Show Values As" selection: the mode name, or the object form (with `params` / `precision`) for modes that take input. `null` clears it. |
| `headerName` | `string \| null` |  |  | User-edited header name overriding `colDef.headerName`. `null` reverts to the colDef value. |

This section details how such state items can be manipulated without having to update Column Definitions.

## Save and Apply State

> **Note**
>
> If you want to save and restore the whole grid rather than manipulate individual column attributes, consider [Grid State](https://www.ag-grid.com/angular-data-grid/grid-state/) instead. It contains all of the Column State properties alongside the other grid state sections — including [Calculated Columns](https://www.ag-grid.com/angular-data-grid/calculated-columns/) added at runtime, which Column State alone cannot recreate — and can be applied on initialisation via `initialState` or at runtime via `api.setState()`.

There are two API methods provided for getting and setting Column State. `api.getColumnState()` gets the current column state and `api.applyColumnState(params)` sets the column state.

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `getColumnState` | `Function` |  |  | Gets the state of the columns. Typically used when saving column state. Module: [`ColumnApiModule`](https://www.ag-grid.com/angular-data-grid/modules/). |
| `applyColumnState` | `Function` |  |  | Applies the state of the columns from a previous state. Returns `false` if one or more columns could not be found. Module: [`ColumnApiModule`](https://www.ag-grid.com/angular-data-grid/modules/). |
| `resetColumnState` | `Function` |  |  | Sets the state back to match the originally provided column definitions. Module: [`ColumnApiModule`](https://www.ag-grid.com/angular-data-grid/modules/). |

The example below demonstrates saving and restoring column state. Try the following:

1. Click 'Save State' to save the Column State.
2. Change some column state, e.g. resize columns, move columns around, apply column sorting or row grouping, or rename an [editable header](https://www.ag-grid.com/angular-data-grid/column-headers/#editable-header-name) from its column menu, etc.
3. Click 'Restore State' and the column state is set back to where it was when you clicked 'Save State'.
4. Click 'Reset State' and the state will go back to what was defined in the Column Definitions.

#### Save and Apply State

```ts
import { Component } from "@angular/core";
import { HttpClient } from "@angular/common/http";
import { AgGridAngular } from "ag-grid-angular";
import "./styles.css";
import {
  AutoGroupColumnDef,
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  ColumnApiModule,
  GridApi,
  GridOptions,
  GridReadyEvent,
  ModuleRegistry,
  SideBarDef,
  enableDevValidations,
} from "ag-grid-community";
import {
  ColumnHeaderEditModule,
  ColumnMenuModule,
  ColumnsToolPanelModule,
  PivotModule,
  RowGroupingPanelModule,
} from "ag-grid-enterprise";
if (process.env.NODE_ENV !== "production") {
  enableDevValidations();
}

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

declare let window: any;

@Component({
  selector: "my-app",
  standalone: true,
  imports: [AgGridAngular],
  template: `<div class="test-container">
    <div class="test-header">
      <div class="example-section">
        <button (click)="saveState()">Save State</button>
        <button (click)="restoreState()">Restore State</button>
        <button (click)="resetState()">Reset State</button>
      </div>
    </div>
    <ag-grid-angular
      style="width: 100%; height: 100%;"
      [columnDefs]="columnDefs"
      [defaultColDef]="defaultColDef"
      [autoGroupColumnDef]="autoGroupColumnDef"
      [sideBar]="sideBar"
      [rowGroupPanelShow]="rowGroupPanelShow"
      [pivotPanelShow]="pivotPanelShow"
      [rowData]="rowData"
      (gridReady)="onGridReady($event)"
    />
  </div> `,
})
export class AppComponent {
  private gridApi!: GridApi<IOlympicData>;

  columnDefs: ColDef[] = [
    { field: "athlete", headerNameEditable: true },
    { field: "age", headerNameEditable: true },
    { field: "country", headerNameEditable: true },
    { field: "sport" },
    { field: "year" },
    { field: "date" },
    { field: "gold" },
    { field: "silver" },
    { field: "bronze" },
    { field: "total" },
  ];
  defaultColDef: ColDef = {
    width: 100,
    enableRowGroup: true,
    enablePivot: true,
    enableValue: true,
  };
  autoGroupColumnDef: AutoGroupColumnDef = {
    minWidth: 200,
  };
  sideBar: SideBarDef | string | string[] | boolean | null = {
    toolPanels: ["columns"],
  };
  rowGroupPanelShow: "always" | "onlyWhenGrouping" | "never" = "always";
  pivotPanelShow: "always" | "onlyWhenPivoting" | "never" = "always";
  rowData!: IOlympicData[];

  constructor(private http: HttpClient) {}

  saveState() {
    window.colState = this.gridApi.getColumnState();
    console.log("column state saved");
  }

  restoreState() {
    if (!window.colState) {
      console.log("no columns state to restore by, you must save state first");
      return;
    }
    this.gridApi.applyColumnState({
      state: window.colState,
      applyOrder: true,
    });
    console.log("column state restored");
  }

  resetState() {
    this.gridApi.resetColumnState();
    console.log("column state reset");
  }

  onGridReady(params: GridReadyEvent<IOlympicData>) {
    this.gridApi = params.api;

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

[Live example: Save and Apply State](https://www.ag-grid.com/examples/column-state/save-apply-state/angular)

## Partial State

It is possible to focus on particular columns and / or particular attributes when getting and / or applying a Column State. This allows fine grained control over the Column State, e.g. setting what Columns are Pinned, without impacting any other state attribute.

### Applying Partial State

When applying a Column State, in cases where some state attributes or columns are missing from the Column State, the following rules apply:

- Attributes that are not supplied or are set to `undefined` will remain unchanged. For example if a Column has a Column State with just `pinned`, then Pinned is applied to that Column but other attributes, such as `sort` are left intact.
- When state is applied and there are additional Columns in the grid that do not appear in the provided state, then the `params.defaultState` is applied to those additional Columns.
- If `params.defaultState` is not provided, then any additional Columns in the grid will not be updated.

Combining these rules together allows flexible fine-grained state control. Take the following code snippets as examples:

```ts
// Sort Athlete column ascending
this.gridApi.applyColumnState({
    state: [
        {
            colId: 'athlete',
            sort: 'asc'
        }
    ]
});

// Sort Athlete column ascending and clear sort on all other columns
this.gridApi.applyColumnState({
    state: [
        {
            colId: 'athlete',
            sort: 'asc'
        }
    ],
    defaultState: {
        // important to say 'null' as undefined means 'do nothing'
        sort: null
    }
});

// Clear sorting on all columns, leave all other attributes untouched
this.gridApi.applyColumnState({
    defaultState: {
        // important to say 'null' as undefined means 'do nothing'
        sort: null
    }
});

// Clear sorting, row group, pivot and pinned on all columns, leave all other attributes untouched
this.gridApi.applyColumnState({
    defaultState: {
        // important to say 'null' as undefined means 'do nothing'
        sort: null,
        rowGroup: null,
        pivot: null,
        pinned: null
    }
});

// Order columns, but do nothing else
this.gridApi.applyColumnState({
    state: [
        { colId: 'athlete' },
        { colId: 'country' },
        { colId: 'age' },
        { colId: 'sport' }
    ],
    applyOrder: true
});
```

The example below shows some fine grained access to Column State.

#### Fine Grained State

```ts
import { Component } from "@angular/core";
import { HttpClient } from "@angular/common/http";
import { AgGridAngular } from "ag-grid-angular";
import "./styles.css";
import {
  AutoGroupColumnDef,
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  ColumnApiModule,
  GridApi,
  GridOptions,
  GridReadyEvent,
  ModuleRegistry,
  SideBarDef,
  enableDevValidations,
} from "ag-grid-community";
import {
  ColumnsToolPanelModule,
  PivotModule,
  RowGroupingPanelModule,
} from "ag-grid-enterprise";
if (process.env.NODE_ENV !== "production") {
  enableDevValidations();
}

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

@Component({
  selector: "my-app",
  standalone: true,
  imports: [AgGridAngular],
  template: `<div class="test-container">
    <div class="test-header">
      <table>
        <tbody>
          <tr>
            <td>Sort:</td>
            <td>
              <button (click)="onBtSortAthlete()">Sort Athlete</button>
              <button (click)="onBtSortCountryThenSportClearOthers()">
                Sort Country, then Sport - Clear Others
              </button>
              <button (click)="onBtClearAllSorting()">Clear All Sorting</button>
            </td>
          </tr>
          <tr>
            <td>Column Order:</td>
            <td>
              <button (click)="onBtOrderColsMedalsFirst()">
                Show Medals First
              </button>
              <button (click)="onBtOrderColsMedalsLast()">
                Show Medals Last
              </button>
            </td>
          </tr>
          <tr>
            <td>Column Visibility:</td>
            <td>
              <button (click)="onBtHideMedals()">Hide Medals</button>
              <button (click)="onBtShowMedals()">Show Medals</button>
            </td>
          </tr>
          <tr>
            <td>Row Group:</td>
            <td>
              <button (click)="onBtRowGroupCountryThenSport()">
                Group Country then Sport
              </button>
              <button (click)="onBtRemoveCountryRowGroup()">
                Remove Country
              </button>
              <button (click)="onBtClearAllRowGroups()">
                Clear All Groups
              </button>
            </td>
          </tr>
        </tbody>
      </table>
    </div>
    <ag-grid-angular
      style="width: 100%; height: 100%;"
      [columnDefs]="columnDefs"
      [defaultColDef]="defaultColDef"
      [autoGroupColumnDef]="autoGroupColumnDef"
      [sideBar]="sideBar"
      [rowGroupPanelShow]="rowGroupPanelShow"
      [pivotPanelShow]="pivotPanelShow"
      [rowData]="rowData"
      (gridReady)="onGridReady($event)"
    />
  </div> `,
})
export class AppComponent {
  private gridApi!: GridApi<IOlympicData>;

  columnDefs: ColDef[] = [
    { field: "athlete" },
    { field: "age" },
    { field: "country" },
    { field: "sport" },
    { field: "year" },
    { field: "date" },
    { field: "gold" },
    { field: "silver" },
    { field: "bronze" },
    { field: "total" },
  ];
  defaultColDef: ColDef = {
    width: 150,
    enableRowGroup: true,
    enablePivot: true,
    enableValue: true,
  };
  autoGroupColumnDef: AutoGroupColumnDef = {
    minWidth: 200,
  };
  sideBar: SideBarDef | string | string[] | boolean | null = {
    toolPanels: ["columns"],
  };
  rowGroupPanelShow: "always" | "onlyWhenGrouping" | "never" = "always";
  pivotPanelShow: "always" | "onlyWhenPivoting" | "never" = "always";
  rowData!: IOlympicData[];

  constructor(private http: HttpClient) {}

  onBtSortAthlete() {
    this.gridApi.applyColumnState({
      state: [{ colId: "athlete", sort: "asc" }],
    });
  }

  onBtSortCountryThenSportClearOthers() {
    this.gridApi.applyColumnState({
      state: [
        { colId: "country", sort: "asc", sortIndex: 0 },
        { colId: "sport", sort: "asc", sortIndex: 1 },
      ],
      defaultState: { sort: null },
    });
  }

  onBtClearAllSorting() {
    this.gridApi.applyColumnState({
      defaultState: { sort: null },
    });
  }

  onBtRowGroupCountryThenSport() {
    this.gridApi.applyColumnState({
      state: [
        { colId: "country", rowGroupIndex: 0 },
        { colId: "sport", rowGroupIndex: 1 },
      ],
      defaultState: { rowGroup: false },
    });
  }

  onBtRemoveCountryRowGroup() {
    this.gridApi.applyColumnState({
      state: [{ colId: "country", rowGroup: false }],
    });
  }

  onBtClearAllRowGroups() {
    this.gridApi.applyColumnState({
      defaultState: { rowGroup: false },
    });
  }

  onBtOrderColsMedalsFirst() {
    this.gridApi.applyColumnState({
      state: [
        { colId: "gold" },
        { colId: "silver" },
        { colId: "bronze" },
        { colId: "total" },
        { colId: "athlete" },
        { colId: "age" },
        { colId: "country" },
        { colId: "sport" },
        { colId: "year" },
        { colId: "date" },
      ],
      applyOrder: true,
    });
  }

  onBtOrderColsMedalsLast() {
    this.gridApi.applyColumnState({
      state: [
        { colId: "athlete" },
        { colId: "age" },
        { colId: "country" },
        { colId: "sport" },
        { colId: "year" },
        { colId: "date" },
        { colId: "gold" },
        { colId: "silver" },
        { colId: "bronze" },
        { colId: "total" },
      ],
      applyOrder: true,
    });
  }

  onBtHideMedals() {
    this.gridApi.applyColumnState({
      state: [
        { colId: "gold", hide: true },
        { colId: "silver", hide: true },
        { colId: "bronze", hide: true },
        { colId: "total", hide: true },
      ],
    });
  }

  onBtShowMedals() {
    this.gridApi.applyColumnState({
      state: [
        { colId: "gold", hide: false },
        { colId: "silver", hide: false },
        { colId: "bronze", hide: false },
        { colId: "total", hide: false },
      ],
    });
  }

  onGridReady(params: GridReadyEvent<IOlympicData>) {
    this.gridApi = params.api;

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

[Live example: Fine Grained State](https://www.ag-grid.com/examples/column-state/fine-grained-state/angular)

### Saving Partial State

Using the techniques above, it is possible to save and restore a subset of the parameters in the state. The example below demonstrates this by selectively saving and restoring a) sort state, and b) column visibility and order state.

Note that when saving and restoring Sort state, other state attributes (width, row group, column order etc) are not impacted.

Likewise when saving and restoring visibility and order, only visibility and order will be impacted when re-applying the state.

#### Selective State

```ts
import { Component } from "@angular/core";
import { HttpClient } from "@angular/common/http";
import { AgGridAngular } from "ag-grid-angular";
import "./styles.css";
import {
  AutoGroupColumnDef,
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  ColumnApiModule,
  GridApi,
  GridOptions,
  GridReadyEvent,
  ModuleRegistry,
  SideBarDef,
  enableDevValidations,
} from "ag-grid-community";
import {
  ColumnsToolPanelModule,
  PivotModule,
  RowGroupingPanelModule,
} from "ag-grid-enterprise";
if (process.env.NODE_ENV !== "production") {
  enableDevValidations();
}

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

declare let window: any;

@Component({
  selector: "my-app",
  standalone: true,
  imports: [AgGridAngular],
  template: `<div class="test-container">
    <div class="test-header">
      <div class="example-section">
        <button (click)="onBtSaveSortState()">Save Sort</button>
        <button (click)="onBtRestoreSortState()">Restore Sort</button>
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
        <button (click)="onBtSaveOrderAndVisibilityState()">
          Save Order &amp; Visibility
        </button>
        <button (click)="onBtRestoreOrderAndVisibilityState()">
          Restore Order &amp; Visibility
        </button>
      </div>
    </div>
    <ag-grid-angular
      style="width: 100%; height: 100%;"
      [columnDefs]="columnDefs"
      [defaultColDef]="defaultColDef"
      [autoGroupColumnDef]="autoGroupColumnDef"
      [sideBar]="sideBar"
      [rowGroupPanelShow]="rowGroupPanelShow"
      [pivotPanelShow]="pivotPanelShow"
      [rowData]="rowData"
      (gridReady)="onGridReady($event)"
    />
  </div> `,
})
export class AppComponent {
  private gridApi!: GridApi<IOlympicData>;

  columnDefs: ColDef[] = [
    { field: "athlete" },
    { field: "age" },
    { field: "country" },
    { field: "sport" },
    { field: "year" },
    { field: "date" },
    { field: "gold" },
    { field: "silver" },
    { field: "bronze" },
    { field: "total" },
  ];
  defaultColDef: ColDef = {
    width: 100,
    enableRowGroup: true,
    enablePivot: true,
    enableValue: true,
  };
  autoGroupColumnDef: AutoGroupColumnDef = {
    minWidth: 200,
  };
  sideBar: SideBarDef | string | string[] | boolean | null = {
    toolPanels: ["columns"],
  };
  rowGroupPanelShow: "always" | "onlyWhenGrouping" | "never" = "always";
  pivotPanelShow: "always" | "onlyWhenPivoting" | "never" = "always";
  rowData!: IOlympicData[];

  constructor(private http: HttpClient) {}

  onBtSaveSortState() {
    const allState = this.gridApi.getColumnState();
    const sortState = allState.map((state) => ({
      colId: state.colId,
      sort: state.sort,
      sortIndex: state.sortIndex,
    }));
    window.sortState = sortState;
    console.log("sort state saved", sortState);
  }

  onBtRestoreSortState() {
    if (!window.sortState) {
      console.log("no sort state to restore, you must save sort state first");
      return;
    }
    this.gridApi.applyColumnState({
      state: window.sortState,
    });
    console.log("sort state restored");
  }

  onBtSaveOrderAndVisibilityState() {
    const allState = this.gridApi.getColumnState();
    const orderAndVisibilityState = allState.map((state) => ({
      colId: state.colId,
      hide: state.hide,
    }));
    window.orderAndVisibilityState = orderAndVisibilityState;
    console.log("order and visibility state saved", orderAndVisibilityState);
  }

  onBtRestoreOrderAndVisibilityState() {
    if (!window.orderAndVisibilityState) {
      console.log(
        "no order and visibility state to restore by, you must save order and visibility state first",
      );
      return;
    }
    this.gridApi.applyColumnState({
      state: window.orderAndVisibilityState,
      applyOrder: true,
    });
    console.log("column state restored");
  }

  onGridReady(params: GridReadyEvent<IOlympicData>) {
    this.gridApi = params.api;

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

[Live example: Selective State](https://www.ag-grid.com/examples/column-state/selective-state/angular)

## Considerations

There are a few items to note on specific state attributes. They are as follows:

### Column IDs

Column state is keyed by [Column ID](https://www.ag-grid.com/angular-data-grid/column-updating-definitions/#matching-columns), so give every column a `colId` or a `field` if you intend to save and re-apply its state. A column with neither is identified by its position in `columnDefs`, which means state saved before a reorder is re-applied to a different column. See [Grid State](https://www.ag-grid.com/angular-data-grid/grid-state/#state-contents) for details.

### null vs undefined

For all state attributes, `undefined` means *"do not apply this attribute"* and `null` means *"clear this attribute"*.

For example setting `sort=null` will clear sort on a column whereas setting `sort=undefined` will leave whatever sort, if any, that is currently present.

The only exception is Column Width. Setting `null` is not supported because width is mandatory - there is no such thing as a Column with no width.

### Row Group and Pivot

There are two attributes representing both Row Group and Pivot. First using the boolean attributes `rowGroup` and `pivot` and then secondly using the index attributes `rowGroupIndex` and `pivotIndex`.

When `getColumnState()` is called, all of `rowGroup`, `pivot`, `rowGroupIndex` and `pivotIndex` are returned. When `applyColumnState()` is called, preference is given to the index variants. For example if both `rowGroup` and `rowGroupIndex` are present, `rowGroupIndex` is applied.

## Column Events

Column Events will get raised when applying a Column State as these events would normally get raised. For example `columnPinned` event will get raised if applying the state results in a column getting pinned or unpinned.

The example below demonstrates events getting raised based on Column State changes. The example logs event information to the console.

#### Column Events

```ts
import { Component } from "@angular/core";
import { HttpClient } from "@angular/common/http";
import { AgGridAngular } from "ag-grid-angular";
import "./styles.css";
import {
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  Column,
  ColumnApiModule,
  ColumnMovedEvent,
  ColumnPinnedEvent,
  ColumnPivotChangedEvent,
  ColumnResizedEvent,
  ColumnRowGroupChangedEvent,
  ColumnValueChangedEvent,
  ColumnVisibleEvent,
  GridApi,
  GridOptions,
  GridReadyEvent,
  ModuleRegistry,
  SortChangedEvent,
  enableDevValidations,
} from "ag-grid-community";
import { PivotModule } from "ag-grid-enterprise";
if (process.env.NODE_ENV !== "production") {
  enableDevValidations();
}

ModuleRegistry.registerModules([
  ColumnApiModule,
  ClientSideRowModelModule,
  PivotModule,
]);
import { IOlympicData } from "./interfaces";

@Component({
  selector: "my-app",
  standalone: true,
  imports: [AgGridAngular],
  template: `<div class="test-container">
    <div class="test-header">
      <div class="test-button-row">
        <div class="test-button-group">
          <button (click)="onBtSortOn()">Sort On</button>
          <br />
          <button (click)="onBtSortOff()">Sort Off</button>
        </div>
        <div class="test-button-group">
          <button (click)="onBtWidthNarrow()">Width Narrow</button>
          <br />
          <button (click)="onBtWidthNormal()">Width Normal</button>
        </div>
        <div class="test-button-group">
          <button (click)="onBtHide()">Hide Cols</button>
          <br />
          <button (click)="onBtShow()">Show Cols</button>
        </div>
        <div class="test-button-group">
          <button (click)="onBtReverseOrder()">Reverse Medal Order</button>
          <br />
          <button (click)="onBtNormalOrder()">Normal Medal Order</button>
        </div>
        <div class="test-button-group">
          <button (click)="onBtRowGroupOn()">Row Group On</button>
          <br />
          <button (click)="onBtRowGroupOff()">Row Group Off</button>
        </div>
        <div class="test-button-group">
          <button (click)="onBtAggFuncOn()">Agg Func On</button>
          <br />
          <button (click)="onBtAggFuncOff()">Agg Func Off</button>
        </div>
        <div class="test-button-group">
          <button (click)="onBtPivotOn()">Pivot On</button>
          <br />
          <button (click)="onBtPivotOff()">Pivot Off</button>
        </div>
        <div class="test-button-group">
          <button (click)="onBtPinnedOn()">Pinned On</button>
          <br />
          <button (click)="onBtPinnedOff()">Pinned Off</button>
        </div>
      </div>
    </div>
    <ag-grid-angular
      style="width: 100%; height: 100%;"
      [columnDefs]="columnDefs"
      [defaultColDef]="defaultColDef"
      [rowData]="rowData"
      (sortChanged)="onSortChanged($event)"
      (columnResized)="onColumnResized($event)"
      (columnVisible)="onColumnVisible($event)"
      (columnPivotChanged)="onColumnPivotChanged($event)"
      (columnRowGroupChanged)="onColumnRowGroupChanged($event)"
      (columnValueChanged)="onColumnValueChanged($event)"
      (columnMoved)="onColumnMoved($event)"
      (columnPinned)="onColumnPinned($event)"
      (gridReady)="onGridReady($event)"
    />
  </div> `,
})
export class AppComponent {
  private gridApi!: GridApi<IOlympicData>;

  columnDefs: ColDef[] = [
    { field: "athlete" },
    { field: "age" },
    { field: "country" },
    { field: "sport" },
    { field: "gold" },
    { field: "silver" },
    { field: "bronze" },
  ];
  defaultColDef: ColDef = {
    width: 150,
    enableRowGroup: true,
    enablePivot: true,
    enableValue: true,
  };
  rowData!: IOlympicData[];

  constructor(private http: HttpClient) {}

  onSortChanged(e: SortChangedEvent) {
    console.log("Event Sort Changed", e);
  }

  onColumnResized(e: ColumnResizedEvent) {
    console.log("Event Column Resized", e);
  }

  onColumnVisible(e: ColumnVisibleEvent) {
    console.log("Event Column Visible", e);
  }

  onColumnPivotChanged(e: ColumnPivotChangedEvent) {
    console.log("Event Pivot Changed", e);
  }

  onColumnRowGroupChanged(e: ColumnRowGroupChangedEvent) {
    console.log("Event Row Group Changed", e);
  }

  onColumnValueChanged(e: ColumnValueChangedEvent) {
    console.log("Event Value Changed", e);
  }

  onColumnMoved(e: ColumnMovedEvent) {
    console.log("Event Column Moved", e);
  }

  onColumnPinned(e: ColumnPinnedEvent) {
    console.log("Event Column Pinned", e);
  }

  onBtSortOn() {
    this.gridApi.applyColumnState({
      state: [
        { colId: "age", sort: "desc" },
        { colId: "athlete", sort: "asc" },
      ],
    });
  }

  onBtSortOff() {
    this.gridApi.applyColumnState({
      defaultState: { sort: null },
    });
  }

  onBtWidthNarrow() {
    this.gridApi.applyColumnState({
      state: [
        { colId: "age", width: 100 },
        { colId: "athlete", width: 100 },
      ],
    });
  }

  onBtWidthNormal() {
    this.gridApi.applyColumnState({
      state: [
        { colId: "age", width: 200 },
        { colId: "athlete", width: 200 },
      ],
    });
  }

  onBtHide() {
    this.gridApi.applyColumnState({
      state: [
        { colId: "age", hide: true },
        { colId: "athlete", hide: true },
      ],
    });
  }

  onBtShow() {
    this.gridApi.applyColumnState({
      defaultState: { hide: false },
    });
  }

  onBtPivotOn() {
    this.gridApi.setGridOption("pivotMode", true);
    this.gridApi.applyColumnState({
      state: [{ colId: "country", pivot: true }],
    });
  }

  onBtPivotOff() {
    this.gridApi.setGridOption("pivotMode", false);
    this.gridApi.applyColumnState({
      defaultState: { pivot: false },
    });
  }

  onBtRowGroupOn() {
    this.gridApi.applyColumnState({
      state: [{ colId: "sport", rowGroup: true }],
    });
  }

  onBtRowGroupOff() {
    this.gridApi.applyColumnState({
      defaultState: { rowGroup: false },
    });
  }

  onBtAggFuncOn() {
    this.gridApi.applyColumnState({
      state: [
        { colId: "gold", aggFunc: "sum" },
        { colId: "silver", aggFunc: "sum" },
        { colId: "bronze", aggFunc: "sum" },
      ],
    });
  }

  onBtAggFuncOff() {
    this.gridApi.applyColumnState({
      defaultState: { aggFunc: null },
    });
  }

  onBtNormalOrder() {
    this.gridApi.applyColumnState({
      state: [
        { colId: "athlete" },
        { colId: "age" },
        { colId: "country" },
        { colId: "sport" },
        { colId: "gold" },
        { colId: "silver" },
        { colId: "bronze" },
      ],
      applyOrder: true,
    });
  }

  onBtReverseOrder() {
    this.gridApi.applyColumnState({
      state: [
        { colId: "athlete" },
        { colId: "age" },
        { colId: "country" },
        { colId: "sport" },
        { colId: "bronze" },
        { colId: "silver" },
        { colId: "gold" },
      ],
      applyOrder: true,
    });
  }

  onBtPinnedOn() {
    this.gridApi.applyColumnState({
      state: [
        { colId: "athlete", pinned: "left" },
        { colId: "sport", pinned: "right" },
      ],
    });
  }

  onBtPinnedOff() {
    this.gridApi.applyColumnState({
      defaultState: { pinned: null },
    });
  }

  onGridReady(params: GridReadyEvent<IOlympicData>) {
    this.gridApi = params.api;

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

[Live example: Column Events](https://www.ag-grid.com/examples/column-state/column-events/angular)

## Column Group State

Column Group State is concerned with the state of Column Groups. There is only one state attribute for Column Groups, which is whether the group is open or closed.

To get the state of Column Groups use the API method `api.getColumnGroupState()`. To set the Column Group state use the API method `api.setColumnGroupState(stateItems)`.

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `getColumnGroupState` | `Function` |  |  | Gets the state of the column groups. Typically used when saving column group state. |
| `setColumnGroupState` | `Function` |  |  | Sets the state of the column group state from a previous state. |
| `resetColumnGroupState` | `Function` |  |  | Sets the state back to match the originally provided column definitions. |

The example below demonstrates getting and setting Column Group State. Note the following:

- Clicking 'Save State' will save the opened / closed state of column groups.
- Clicking 'Restore State' will restore the previously saved state.
- Clicking 'Reset State' will reset the column state to match the Column Definitions, i.e. all Column Groups will be closed.

#### Column Group State

```ts
import { Component } from "@angular/core";
import { HttpClient } from "@angular/common/http";
import { AgGridAngular } from "ag-grid-angular";
import "./styles.css";
import {
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  GridApi,
  GridOptions,
  GridReadyEvent,
  ModuleRegistry,
  enableDevValidations,
} from "ag-grid-community";
import { RowGroupingModule } from "ag-grid-enterprise";
if (process.env.NODE_ENV !== "production") {
  enableDevValidations();
}

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

declare let window: any;

@Component({
  selector: "my-app",
  standalone: true,
  imports: [AgGridAngular],
  template: `<div class="test-container">
    <div class="test-header">
      <div class="example-section">
        Column State:
        <button (click)="saveState()">Save State</button>
        <button (click)="restoreState()">Restore State</button>
        <button (click)="resetState()">Reset State</button>
      </div>
    </div>
    <ag-grid-angular
      style="width: 100%; height: 100%;"
      [columnDefs]="columnDefs"
      [defaultColDef]="defaultColDef"
      [rowData]="rowData"
      (gridReady)="onGridReady($event)"
    />
  </div> `,
})
export class AppComponent {
  private gridApi!: GridApi<IOlympicData>;

  columnDefs: (ColDef | ColGroupDef)[] = [
    {
      headerName: "Athlete",
      children: [
        { field: "athlete" },
        { field: "country", columnGroupShow: "open" },
        { field: "sport", columnGroupShow: "open" },
        { field: "year", columnGroupShow: "open" },
        { field: "date", columnGroupShow: "open" },
      ],
    },
    {
      headerName: "Medals",
      children: [
        { field: "total", columnGroupShow: "closed" },
        { field: "gold", columnGroupShow: "open" },
        { field: "silver", columnGroupShow: "open" },
        { field: "bronze", columnGroupShow: "open" },
      ],
    },
  ];
  defaultColDef: ColDef = {
    width: 150,
  };
  rowData!: IOlympicData[];

  constructor(private http: HttpClient) {}

  saveState() {
    window.groupState = this.gridApi.getColumnGroupState();
    console.log("group state saved", window.groupState);
    console.log("column group state saved");
  }

  restoreState() {
    if (!window.groupState) {
      console.log("no columns state to restore by, you must save state first");
      return;
    }
    this.gridApi.setColumnGroupState(window.groupState);
    console.log("column group state restored");
  }

  resetState() {
    this.gridApi.resetColumnGroupState();
    console.log("column group state reset");
  }

  onGridReady(params: GridReadyEvent<IOlympicData>) {
    this.gridApi = params.api;

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

[Live example: Column Group State](https://www.ag-grid.com/examples/column-state/column-group-state/angular)
