---
title: "Updating Column Definitions"
framework: vue
version: "36.1.0"
---

# Updating Column Definitions

The section [Column Definitions](https://www.ag-grid.com/vue-data-grid/column-definitions/) explained how to configure columns. It is possible to change the configuration of the Columns after they are initially set. This section goes through how to update Column Definitions.

## Adding & Removing Columns

It is possible to add and remove columns by updating the list of Column Definitions provided to the grid.

When new columns are set, the grid will compare with current columns and work out which columns are old (to be removed), new (new columns created) or kept.

The example below demonstrates adding and removing columns from a grid. Note the following:

- Selecting the buttons to toggle between including or excluding the medal columns.

#### Add & Remove Columns

```ts
import {
  createApp,
  defineComponent,
  onBeforeMount,
  ref,
  shallowRef,
} from "vue";
import { AgGridVue } from "ag-grid-vue3";
import "./styles.css";
import {
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  GridApi,
  GridOptions,
  GridReadyEvent,
  ModuleRegistry,
  enableDevValidations,
} from "ag-grid-community";
import { IOlympicData } from "./interfaces";
if (process.env.NODE_ENV !== "production") {
  enableDevValidations();
}

ModuleRegistry.registerModules([ClientSideRowModelModule]);

const columnDefsMedalsIncluded: ColDef[] = [
  { field: "athlete" },
  { field: "gold" },
  { field: "silver" },
  { field: "bronze" },
  { field: "total" },
  { field: "age" },
  { field: "country" },
  { field: "sport" },
  { field: "year" },
  { field: "date" },
];

const colDefsMedalsExcluded: ColDef[] = [
  { field: "athlete" },
  { field: "age" },
  { field: "country" },
  { field: "sport" },
  { field: "year" },
  { field: "date" },
];

const VueExample = defineComponent({
  template: `
        <div style="height: 100%">
                <div class="test-container">
      <div class="test-header">
        <button v-on:click="onBtExcludeMedalColumns()">Exclude Medal Columns</button>
        <button v-on:click="onBtIncludeMedalColumns()">Include Medal Columns</button>
      </div>
      <ag-grid-vue
        style="width: 100%; height: 100%;"
        class="test-grid"
        @grid-ready="onGridReady"
        :columnDefs="columnDefs"
        :defaultColDef="defaultColDef"
        :rowData="rowData"></ag-grid-vue>
      </div>
        </div>
    `,
  components: {
    "ag-grid-vue": AgGridVue,
  },
  setup(props) {
    const gridApi = shallowRef<GridApi<IOlympicData> | null>(null);
    const columnDefs = ref<ColDef[]>(columnDefsMedalsIncluded);
    const defaultColDef = ref<ColDef>({
      initialWidth: 100,
    });
    const rowData = ref<IOlympicData[]>(null);

    function onBtExcludeMedalColumns() {
      gridApi.value!.setGridOption("columnDefs", colDefsMedalsExcluded);
    }
    function onBtIncludeMedalColumns() {
      gridApi.value!.setGridOption("columnDefs", columnDefsMedalsIncluded);
    }
    const onGridReady = (params: GridReadyEvent) => {
      gridApi.value = params.api;

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

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

    return {
      gridApi,
      columnDefs,
      defaultColDef,
      rowData,
      onGridReady,
      onBtExcludeMedalColumns,
      onBtIncludeMedalColumns,
    };
  },
});

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

[Live example: Add & Remove Columns](https://www.ag-grid.com/examples/column-updating-definitions/add-remove-columns/vue3)

In the example above, note that any state applied to any column (e.g. sort, filter, width) will be kept if the column still exists after the new definitions are applied. For example try the following:

- Resize Country column. Note changing columns doesn't impact its width.
- Sort Country column. Note changing columns doesn't impact its sort.

## Updating Column Definitions

All properties of a column definition, except those marked as [Initial](https://www.ag-grid.com/vue-data-grid/column-interface/#initial-column-options), can be updated. For example if you want to change the Header Name of a column, you update the `headerName` on the Column Definition and then set the list of Column Definitions into the grid again.

It is not possible to update the Column Definition of just one column in isolation. Only a new set of Column Definitions can be applied.

The example below demonstrates updating column definitions to change how columns are configured. Note the following:

- All Columns are provided with just the `field` attribute set on the Column Definition.
- 'Set Header Names' and 'Remove Header Names' sets and then subsequently removes the `headerName` attribute on all Columns.
- 'Set Value Formatters' and 'Remove Value Formatters' sets and then subsequently removes the `valueFormatter` attribute on all Columns.
- Note that any resizing, sorting etc of the Columns is kept intact between updates to the Column Definitions.

#### Updating Column Definition

```ts
import {
  createApp,
  defineComponent,
  onBeforeMount,
  ref,
  shallowRef,
} from "vue";
import { AgGridVue } from "ag-grid-vue3";
import "./styles.css";
import {
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  GridApi,
  GridOptions,
  GridReadyEvent,
  ModuleRegistry,
  NumberFilterModule,
  TextFilterModule,
  enableDevValidations,
} from "ag-grid-community";
import { IOlympicData } from "./interfaces";
if (process.env.NODE_ENV !== "production") {
  enableDevValidations();
}

ModuleRegistry.registerModules([
  TextFilterModule,
  NumberFilterModule,
  ClientSideRowModelModule,
]);

const COL_DEFS: ColDef<IOlympicData>[] = [
  { field: "athlete" },
  { field: "age" },
  { field: "country" },
  { field: "sport" },
  { field: "year" },
  { field: "date" },
  { field: "gold" },
  { field: "silver" },
  { field: "bronze" },
  { field: "total" },
];

const VueExample = defineComponent({
  template: `
        <div style="height: 100%">
                <div class="test-container">
      <div class="test-header">
        <button v-on:click="setHeaderNames()">Set Header Names</button>
        <button v-on:click="removeHeaderNames()">Remove Header Names</button>
        <button v-on:click="setValueFormatters()">Set Value Formatters</button>
        <button v-on:click="removeValueFormatters()">Remove Value Formatters</button>
      </div>
      <ag-grid-vue
        style="width: 100%; height: 100%;"
        class="test-grid"
        @grid-ready="onGridReady"
        :defaultColDef="defaultColDef"
        :columnDefs="columnDefs"
        :rowData="rowData"></ag-grid-vue>
      </div>
        </div>
    `,
  components: {
    "ag-grid-vue": AgGridVue,
  },
  setup(props) {
    const gridApi = shallowRef<GridApi<IOlympicData> | null>(null);
    const defaultColDef = ref<ColDef>({
      initialWidth: 100,
      filter: true,
    });
    const columnDefs = ref<ColDef[]>(COL_DEFS);
    const rowData = ref<IOlympicData[]>(null);

    function setHeaderNames() {
      COL_DEFS.forEach((colDef, index) => {
        colDef.headerName = "C" + index;
      });
      gridApi.value!.setGridOption("columnDefs", COL_DEFS);
    }
    function removeHeaderNames() {
      COL_DEFS.forEach((colDef) => {
        colDef.headerName = undefined;
      });
      gridApi.value!.setGridOption("columnDefs", COL_DEFS);
    }
    function setValueFormatters() {
      COL_DEFS.forEach((colDef) => {
        colDef.valueFormatter = function (params) {
          return "[ " + params.value + " ]";
        };
      });
      gridApi.value!.setGridOption("columnDefs", COL_DEFS);
    }
    function removeValueFormatters() {
      COL_DEFS.forEach((colDef) => {
        colDef.valueFormatter = undefined;
      });
      gridApi.value!.setGridOption("columnDefs", COL_DEFS);
    }
    const onGridReady = (params: GridReadyEvent) => {
      gridApi.value = params.api;

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

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

    return {
      gridApi,
      defaultColDef,
      columnDefs,
      rowData,
      onGridReady,
      setHeaderNames,
      removeHeaderNames,
      setValueFormatters,
      removeValueFormatters,
    };
  },
});

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

[Live example: Updating Column Definition](https://www.ag-grid.com/examples/column-updating-definitions/update-column-definition/vue3)

## Changing Column State

Parts of the Column Definitions represent Column State. Column State is stateful information and represents changing values of the grid.

All stateful attributes of Column Definitions are as follows:

| Stateful Attribute | Initial Attribute | Description |
| --- | --- | --- |
| width | initialWidth | Width of the column. |
| flex | initialFlex | The flex value for setting this column's width. |
| hide | initialHide | Whether this column should be hidden. |
| pinned | initialPinned | Whether this column should be pinned. |
| sort | initialSort | The sort to apply to this column. |
| sortIndex | initialSortIndex | The order to apply sorting, if multi column sorting. |
| rowGroup | initialRowGroup | Whether this column should be a row group. |
| rowGroupIndex | initialRowGroupIndex | Whether this column should be a row group and in what order. |
| pivot | initialPivot | If this column should be a pivot. |
| pivotIndex | initialPivotIndex | Whether this column should be a pivot and in what order. |
| aggFunc | initialAggFunc | The function to aggregate this column by if row grouping or pivoting. |
| showValuesAs | initialShowValuesAs | The mode used to show this column's values relative to another value. |

> **Note**
>
> If you are interested in changing Column State only and not the other parts of the column definitions, then consider working with the [Column State](https://www.ag-grid.com/vue-data-grid/column-state/) API instead.
>
> Column State is provided as part of Column Definitions to enable these properties to be reactive. Some developers wish to update Column Definitions and expect the grid to respond. Other developers may find this non-intuitive and will prefer interacting with [Column State](https://www.ag-grid.com/vue-data-grid/column-state/) directly.

The **Initial Attribute** will be used only when the **Column is Created**. The **Stateful Attribute** will be used when the **Column is Created or Updated**.

```ts
<ag-grid-vue
    :columnDefs="columnDefs"
    /* other grid options ... */>
</ag-grid-vue>

this.columnDefs = [
    // using initial values, get applied when Column is created
    { field: 'country', initialWidth: 200, initialPinned: 'left' },
    // using stateful values, get applied when Column is created or updated
    { field: 'country', width: 200, pinned: 'left' }
];
```

### Initial Attributes

The example below shows Column Definitions using **initial attributes**. Note the following:

- The `initialWidth`, `initialSort` and `initialPinned` are applied only when the columns are created.
- If you update the width, sort or pinned of a column by interacting with the grid's UI and then hit 'Set Columns with Initials', the columns state will not change.
- Removing the columns first and then setting them again will use the initial values again.

#### Updating Column Initial Attributes

```ts
import {
  createApp,
  defineComponent,
  onBeforeMount,
  ref,
  shallowRef,
} from "vue";
import { AgGridVue } from "ag-grid-vue3";
import "./styles.css";
import {
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  ColumnApiModule,
  GridApi,
  GridOptions,
  GridReadyEvent,
  ModuleRegistry,
  enableDevValidations,
} from "ag-grid-community";
import { IOlympicData } from "./interfaces";
if (process.env.NODE_ENV !== "production") {
  enableDevValidations();
}

ModuleRegistry.registerModules([ColumnApiModule, ClientSideRowModelModule]);

function getColumnDefs(): ColDef[] {
  return [
    { field: "athlete", initialWidth: 100, initialSort: "asc" },
    { field: "age" },
    { field: "country", initialPinned: "left" },
    { field: "sport" },
    { field: "year" },
    { field: "date" },
    { field: "gold" },
    { field: "silver" },
    { field: "bronze" },
    { field: "total" },
  ];
}

const VueExample = defineComponent({
  template: `
        <div style="height: 100%">
                <div class="test-container">
      <div class="test-header">
        <button v-on:click="onBtWithDefault()">Set Columns with Initials</button>
        <button v-on:click="onBtRemove()">Remove Columns</button>
      </div>
      <ag-grid-vue
        style="width: 100%; height: 100%;"
        class="test-grid"
        @grid-ready="onGridReady"
        :defaultColDef="defaultColDef"
        :columnDefs="columnDefs"
        :rowData="rowData"></ag-grid-vue>
      </div>
        </div>
    `,
  components: {
    "ag-grid-vue": AgGridVue,
  },
  setup(props) {
    const gridApi = shallowRef<GridApi<IOlympicData> | null>(null);
    const defaultColDef = ref<ColDef>({
      initialWidth: 100,
    });
    const columnDefs = ref<ColDef[]>(getColumnDefs());
    const rowData = ref<IOlympicData[]>(null);

    function onBtWithDefault() {
      gridApi.value!.setGridOption("columnDefs", getColumnDefs());
    }
    function onBtRemove() {
      gridApi.value!.setGridOption("columnDefs", []);
    }
    const onGridReady = (params: GridReadyEvent) => {
      gridApi.value = params.api;

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

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

    return {
      gridApi,
      defaultColDef,
      columnDefs,
      rowData,
      onGridReady,
      onBtWithDefault,
      onBtRemove,
    };
  },
});

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

[Live example: Updating Column Initial Attributes](https://www.ag-grid.com/examples/column-updating-definitions/changing-default/vue3)

### Stateful Attributes

The following example shows Column Definitions using **stateful attributes**. Note the following:

- The `width`, `sort` and `pinned` stateful attributes are applied whenever Column Definitions are set.
- If you update the width, sort or pinned of a column by interacting with the grid's UI and then hit 'Set Columns with State', the columns state will change and the changes made via the UI will be lost.
- Note the `defaultColDef` is used to remove state. For example `sort=null` is set so that any sorting the user might have done on another column is cleared down. Otherwise, the grid would see the `sort` attribute as `undefined` which means the state should not be changed.

#### Updating Column State

```ts
import {
  createApp,
  defineComponent,
  onBeforeMount,
  ref,
  shallowRef,
} from "vue";
import { AgGridVue } from "ag-grid-vue3";
import "./styles.css";
import {
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  ColumnApiModule,
  GridApi,
  GridOptions,
  GridReadyEvent,
  ModuleRegistry,
  enableDevValidations,
} from "ag-grid-community";
import { IOlympicData } from "./interfaces";
if (process.env.NODE_ENV !== "production") {
  enableDevValidations();
}

ModuleRegistry.registerModules([ColumnApiModule, ClientSideRowModelModule]);

function getColumnDefs(): ColDef[] {
  return [
    { field: "athlete", width: 150, sort: "asc" },
    { field: "age" },
    { field: "country", pinned: "left" },
    { field: "sport" },
    { field: "year" },
    { field: "date" },
    { field: "gold" },
    { field: "silver" },
    { field: "bronze" },
    { field: "total" },
  ];
}

const VueExample = defineComponent({
  template: `
        <div style="height: 100%">
                <div class="test-container">
      <div class="test-header">
        <button v-on:click="onBtWithState()">Set Columns with State</button>
        <button v-on:click="onBtRemove()">Remove Columns</button>
      </div>
      <ag-grid-vue
        style="width: 100%; height: 100%;"
        class="test-grid"
        @grid-ready="onGridReady"
        :defaultColDef="defaultColDef"
        :columnDefs="columnDefs"
        :rowData="rowData"></ag-grid-vue>
      </div>
        </div>
    `,
  components: {
    "ag-grid-vue": AgGridVue,
  },
  setup(props) {
    const gridApi = shallowRef<GridApi<IOlympicData> | null>(null);
    const defaultColDef = ref<ColDef>({
      width: 100, // resets col widths if manually resized
      pinned: null, // important - clears pinned if not specified in col def
      sort: null, // important - clears sort if not specified in col def
    });
    const columnDefs = ref<ColDef[]>(getColumnDefs());
    const rowData = ref<IOlympicData[]>(null);

    function onBtWithState() {
      gridApi.value!.setGridOption("columnDefs", getColumnDefs());
    }
    function onBtRemove() {
      gridApi.value!.setGridOption("columnDefs", []);
    }
    const onGridReady = (params: GridReadyEvent) => {
      gridApi.value = params.api;

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

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

    return {
      gridApi,
      defaultColDef,
      columnDefs,
      rowData,
      onGridReady,
      onBtWithState,
      onBtRemove,
    };
  },
});

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

[Live example: Updating Column State](https://www.ag-grid.com/examples/column-updating-definitions/changing-state/vue3)

## null vs undefined

When a stateful attribute is set to `undefined` the grid ignores the attribute.

When a stateful attribute is set to `null` the grid clears the attribute.

For example the setting `pinned=null` will clear pinning on a column whereas `pinned=undefined` means the grid will leave pinned state as it is for that column.

If you don't want to upset any column state (e.g. if you don't want to undo any change the user has made to the columns via the grid's UI, such as applying a sort by clicking on a header, or dragging a column's width) then do not set the state attributes as by default they will be `undefined`.

## Matching Columns

When a new Column Definition is passed to the grid, the grid needs to work out if it's an update of a Column or a new Column.

Most of the time the `field` attribute will match the Column. However `field` is both an optional and non-unique attribute, e.g. a `valueGetter` could be used instead of field, or two columns could share the same field.

Given the `field` is not a unique identifier, the grid uses the following rules to match columns:

1. If `colId` provided, match using `colId`
2. Otherwise if `field` provided, match using `field`
3. Otherwise match using object equality on Column Definition instance

In other words, to have the grid correctly match Columns make sure each Column has either a `field` or `colId`.

Matching by Column Definition instance only works within the lifetime of a grid, so a `field` or `colId` is required if you save and restore [Grid State](https://www.ag-grid.com/vue-data-grid/grid-state/) or [Column State](https://www.ag-grid.com/vue-data-grid/column-state/). A column with neither is identified by its position, and its state is re-applied to whichever column later occupies that position.

The example below demonstrates the different matching strategies. Note the following:

- All columns, with the exception of Country, are matched correctly. This means any column width, sort etc will be kept between changes to the columns. Country will have its state reset, as it will be treated as a new column each time.
- Athlete column is matched by object equality as the same column definition instance is provided to the grid each time.
- Age column is matched by `colId`. The `colId` is needed as the column has no `field` attribute.
- All other columns except Country are matched using the `field` attribute.
- Country column is not matched as it's a different object instance and has no `colId` or `field` attributes.

#### Matching Columns

```ts
import {
  createApp,
  defineComponent,
  onBeforeMount,
  ref,
  shallowRef,
} from "vue";
import { AgGridVue } from "ag-grid-vue3";
import "./styles.css";
import {
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  GridApi,
  GridOptions,
  GridReadyEvent,
  ModuleRegistry,
  ValueGetterParams,
  enableDevValidations,
} from "ag-grid-community";
import { IOlympicData } from "./interfaces";
if (process.env.NODE_ENV !== "production") {
  enableDevValidations();
}

ModuleRegistry.registerModules([ClientSideRowModelModule]);

const athleteColumn = {
  headerName: "Athlete",
  valueGetter: (params: ValueGetterParams<IOlympicData>) => {
    return params.data ? params.data.athlete : undefined;
  },
};

function getColDefsMedalsIncluded(): ColDef<IOlympicData>[] {
  return [
    athleteColumn,
    {
      colId: "myAgeCol",
      headerName: "Age",
      valueGetter: (params: ValueGetterParams<IOlympicData>) => {
        return params.data ? params.data.age : undefined;
      },
    },
    {
      headerName: "Country",
      headerClass: "country-header",
      valueGetter: (params: ValueGetterParams<IOlympicData>) => {
        return params.data ? params.data.country : undefined;
      },
    },
    { field: "sport" },
    { field: "year" },
    { field: "date" },
    { field: "gold" },
    { field: "silver" },
    { field: "bronze" },
    { field: "total" },
  ];
}

function getColDefsMedalsExcluded(): ColDef<IOlympicData>[] {
  return [
    athleteColumn,
    {
      colId: "myAgeCol",
      headerName: "Age",
      valueGetter: (params: ValueGetterParams<IOlympicData>) => {
        return params.data ? params.data.age : undefined;
      },
    },
    {
      headerName: "Country",
      headerClass: "country-header",
      valueGetter: (params: ValueGetterParams<IOlympicData>) => {
        return params.data ? params.data.country : undefined;
      },
    },
    { field: "sport" },
    { field: "year" },
    { field: "date" },
  ];
}

const VueExample = defineComponent({
  template: `
        <div style="height: 100%">
                <div class="test-container">
      <div class="test-header">
        <button v-on:click="onBtIncludeMedalColumns()">Include Medal Columns</button>
        <button v-on:click="onBtExcludeMedalColumns()">Exclude Medal Columns</button>
      </div>
      <ag-grid-vue
        style="width: 100%; height: 100%;"
        class="test-grid"
        @grid-ready="onGridReady"
        :defaultColDef="defaultColDef"
        :columnDefs="columnDefs"
        :rowData="rowData"></ag-grid-vue>
      </div>
        </div>
    `,
  components: {
    "ag-grid-vue": AgGridVue,
  },
  setup(props) {
    const gridApi = shallowRef<GridApi<IOlympicData> | null>(null);
    const defaultColDef = ref<ColDef>({
      initialWidth: 100,
    });
    const columnDefs = ref<ColDef[]>(getColDefsMedalsIncluded());
    const rowData = ref<IOlympicData[]>(null);

    function onBtExcludeMedalColumns() {
      gridApi.value!.setGridOption("columnDefs", getColDefsMedalsExcluded());
    }
    function onBtIncludeMedalColumns() {
      gridApi.value!.setGridOption("columnDefs", getColDefsMedalsIncluded());
    }
    const onGridReady = (params: GridReadyEvent) => {
      gridApi.value = params.api;

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

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

    return {
      gridApi,
      defaultColDef,
      columnDefs,
      rowData,
      onGridReady,
      onBtExcludeMedalColumns,
      onBtIncludeMedalColumns,
    };
  },
});

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

[Live example: Matching Columns](https://www.ag-grid.com/examples/column-updating-definitions/matching-columns/vue3)

## Maintain Column Order

When providing new [Column Definitions](https://www.ag-grid.com/vue-data-grid/column-definitions/) to the grid, the order in which they are provided is the order in which the columns are displayed. This can mean that when overwriting columns with a new set of columns, any columns moved by the user will have their position reset.

If you instead want to prioritise the order of the columns as they appear in the grid, set the grid property `maintainColumnOrder` to `true`.

```ts
<ag-grid-vue
    :maintainColumnOrder="maintainColumnOrder"
    /* other grid options ... */>
</ag-grid-vue>

this.maintainColumnOrder = true;
```

In the example below, note the following:

- The grid is configured with `maintainColumnOrder=true`.
- The columns can be reordered by dragging them.
- Two buttons exist, **Column Set A** and **Column Set B**. Clicking these buttons will swap between two column definitions, each with a different order of columns.
- Swapping between the column sets does not reset or change the column order, instead preserving the grid state.
- A **Clear** button also exists, when clicking this the columns are removed, and subsequently applying a column set applies their order.

#### Column Definition Order

```ts
import {
  createApp,
  defineComponent,
  onBeforeMount,
  ref,
  shallowRef,
} from "vue";
import { AgGridVue } from "ag-grid-vue3";
import "./styles.css";
import {
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  GridApi,
  GridOptions,
  GridReadyEvent,
  ModuleRegistry,
  NumberFilterModule,
  TextFilterModule,
  enableDevValidations,
} from "ag-grid-community";
import { IOlympicData } from "./interfaces";
if (process.env.NODE_ENV !== "production") {
  enableDevValidations();
}

ModuleRegistry.registerModules([
  TextFilterModule,
  NumberFilterModule,
  ClientSideRowModelModule,
]);

function getColumnDefsA(): ColDef[] {
  return [
    { field: "athlete", headerName: "A Athlete" },
    { field: "age", headerName: "A Age" },
    { field: "country", headerName: "A Country" },
    { field: "sport", headerName: "A Sport" },
    { field: "year", headerName: "A Year" },
    { field: "date", headerName: "A Date" },
    { field: "gold", headerName: "A Gold" },
    { field: "silver", headerName: "A Silver" },
    { field: "bronze", headerName: "A Bronze" },
    { field: "total", headerName: "A Total" },
  ];
}

function getColumnDefsB(): ColDef[] {
  return [
    { field: "gold", headerName: "B Gold" },
    { field: "silver", headerName: "B Silver" },
    { field: "bronze", headerName: "B Bronze" },
    { field: "total", headerName: "B Total" },
    { field: "athlete", headerName: "B Athlete" },
    { field: "age", headerName: "B Age" },
    { field: "country", headerName: "B Country" },
    { field: "sport", headerName: "B Sport" },
    { field: "year", headerName: "B Year" },
    { field: "date", headerName: "B Date" },
  ];
}

const VueExample = defineComponent({
  template: `
        <div style="height: 100%">
                <div class="test-container">
      <div class="test-header">
        <button v-on:click="setColsA()">Column Set A</button>
        <button v-on:click="setColsB()">Column Set B</button>
        <button v-on:click="clearColDefs()">Clear</button>
      </div>
      <ag-grid-vue
        style="width: 100%; height: 100%;"
        class="test-grid"
        @grid-ready="onGridReady"
        :defaultColDef="defaultColDef"
        :maintainColumnOrder="true"
        :columnDefs="columnDefs"
        :rowData="rowData"></ag-grid-vue>
      </div>
        </div>
    `,
  components: {
    "ag-grid-vue": AgGridVue,
  },
  setup(props) {
    const gridApi = shallowRef<GridApi<IOlympicData> | null>(null);
    const defaultColDef = ref<ColDef>({
      initialWidth: 100,
      filter: true,
    });
    const columnDefs = ref<ColDef[]>(getColumnDefsA());
    const rowData = ref<IOlympicData[]>(null);

    function setColsA() {
      gridApi.value!.setGridOption("columnDefs", getColumnDefsA());
    }
    function setColsB() {
      gridApi.value!.setGridOption("columnDefs", getColumnDefsB());
    }
    function clearColDefs() {
      gridApi.value!.setGridOption("columnDefs", []);
    }
    const onGridReady = (params: GridReadyEvent) => {
      gridApi.value = params.api;

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

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

    return {
      gridApi,
      defaultColDef,
      columnDefs,
      rowData,
      onGridReady,
      setColsA,
      setColsB,
      clearColDefs,
    };
  },
});

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

[Live example: Column Definition Order](https://www.ag-grid.com/examples/column-updating-definitions/col-def-order/vue3)

If there are new Columns added, then these new Columns will always be added at the end.

In order for the Column Order to be maintained, the grid needs to match the Columns. This can be done by ensuring each Column has a unique `field` or `colId` defined. Any Columns that can't be matched will be treated as new Columns and placed at the end.

## Column Events

Column Events will get raised when setting new Column Definitions that update the current Columns. 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 Definition changes. The example logs event information to the console.

#### Column Events

```ts
import {
  createApp,
  defineComponent,
  onBeforeMount,
  ref,
  shallowRef,
} from "vue";
import { AgGridVue } from "ag-grid-vue3";
import "./styles.css";
import {
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  ColumnApiModule,
  ColumnMovedEvent,
  ColumnPinnedEvent,
  ColumnPivotChangedEvent,
  ColumnResizedEvent,
  ColumnRowGroupChangedEvent,
  ColumnValueChangedEvent,
  ColumnVisibleEvent,
  GridApi,
  GridOptions,
  GridReadyEvent,
  ModuleRegistry,
  SortChangedEvent,
  enableDevValidations,
} from "ag-grid-community";
import { PivotModule } from "ag-grid-enterprise";
import { IOlympicData } from "./interfaces";
if (process.env.NODE_ENV !== "production") {
  enableDevValidations();
}

ModuleRegistry.registerModules([
  ColumnApiModule,
  ClientSideRowModelModule,
  PivotModule,
]);

function getColumnDefs(): ColDef[] {
  return [
    { field: "athlete" },
    { field: "age" },
    { field: "country" },
    { field: "sport" },
    { field: "gold" },
    { field: "silver" },
    { field: "bronze" },
  ];
}

const VueExample = defineComponent({
  template: `
        <div style="height: 100%">
                <div class="test-container">
      <div class="test-header">
        <div class="test-button-row">
          <div class="test-button-group">
            <button v-on:click="onBtSortOn()">Sort On</button>
            <br />
            <button v-on:click="onBtSortOff()">Sort Off</button>
          </div>
          <div class="test-button-group">
            <button v-on:click="onBtWidthNarrow()">Width Narrow</button>
            <br />
            <button v-on:click="onBtWidthNormal()">Width Normal</button>
          </div>
          <div class="test-button-group">
            <button v-on:click="onBtHide()">Hide Cols</button>
            <br />
            <button v-on:click="onBtShow()">Show Cols</button>
          </div>
          <div class="test-button-group">
            <button v-on:click="onBtPivotOn()">Pivot On</button>
            <br />
            <button v-on:click="onBtPivotOff()">Pivot Off</button>
          </div>
          <div class="test-button-group">
            <button v-on:click="onBtRowGroupOn()">Row Group On</button>
            <br />
            <button v-on:click="onBtRowGroupOff()">Row Group Off</button>
          </div>
          <div class="test-button-group">
            <button v-on:click="onBtAggFuncOn()">Agg Func On</button>
            <br />
            <button v-on:click="onBtAggFuncOff()">Agg Func Off</button>
          </div>
          <div class="test-button-group">
            <button v-on:click="onBtPinnedOn()">Pinned On</button>
            <br />
            <button v-on:click="onBtPinnedOff()">Pinned Off</button>
          </div>
        </div>
      </div>
      <ag-grid-vue
        style="width: 100%; height: 100%;"
        @grid-ready="onGridReady"
        :defaultColDef="defaultColDef"
        :columnDefs="columnDefs"
        :rowData="rowData"
        @sort-changed="onSortChanged"
        @column-resized="onColumnResized"
        @column-visible="onColumnVisible"
        @column-pivot-changed="onColumnPivotChanged"
        @column-row-group-changed="onColumnRowGroupChanged"
        @column-value-changed="onColumnValueChanged"
        @column-moved="onColumnMoved"
        @column-pinned="onColumnPinned"></ag-grid-vue>
      </div>
        </div>
    `,
  components: {
    "ag-grid-vue": AgGridVue,
  },
  setup(props) {
    const gridApi = shallowRef<GridApi<IOlympicData> | null>(null);
    const defaultColDef = ref<ColDef>({
      width: 150,
      enableRowGroup: true,
      enablePivot: true,
      enableValue: true,
    });
    const columnDefs = ref<ColDef[]>(getColumnDefs());
    const rowData = ref<IOlympicData[]>(null);

    function onSortChanged(e: SortChangedEvent) {
      console.log("Event Sort Changed", e);
    }
    function onColumnResized(e: ColumnResizedEvent) {
      console.log("Event Column Resized", e);
    }
    function onColumnVisible(e: ColumnVisibleEvent) {
      console.log("Event Column Visible", e);
    }
    function onColumnPivotChanged(e: ColumnPivotChangedEvent) {
      console.log("Event Pivot Changed", e);
    }
    function onColumnRowGroupChanged(e: ColumnRowGroupChangedEvent) {
      console.log("Event Row Group Changed", e);
    }
    function onColumnValueChanged(e: ColumnValueChangedEvent) {
      console.log("Event Value Changed", e);
    }
    function onColumnMoved(e: ColumnMovedEvent) {
      console.log("Event Column Moved", e);
    }
    function onColumnPinned(e: ColumnPinnedEvent) {
      console.log("Event Column Pinned", e);
    }
    function onBtSortOn() {
      const columnDefs: ColDef[] = getColumnDefs();
      columnDefs.forEach((colDef) => {
        if (colDef.field === "age") {
          colDef.sort = "desc";
        }
        if (colDef.field === "athlete") {
          colDef.sort = "asc";
        }
      });
      gridApi.value!.setGridOption("columnDefs", columnDefs);
    }
    function onBtSortOff() {
      const columnDefs: ColDef[] = getColumnDefs();
      columnDefs.forEach((colDef) => {
        colDef.sort = null;
      });
      gridApi.value!.setGridOption("columnDefs", columnDefs);
    }
    function onBtWidthNarrow() {
      const columnDefs: ColDef[] = getColumnDefs();
      columnDefs.forEach((colDef) => {
        if (colDef.field === "age" || colDef.field === "athlete") {
          colDef.width = 100;
        }
      });
      gridApi.value!.setGridOption("columnDefs", columnDefs);
    }
    function onBtWidthNormal() {
      const columnDefs: ColDef[] = getColumnDefs();
      columnDefs.forEach((colDef) => {
        colDef.width = 200;
      });
      gridApi.value!.setGridOption("columnDefs", columnDefs);
    }
    function onBtHide() {
      const columnDefs: ColDef[] = getColumnDefs();
      columnDefs.forEach((colDef) => {
        if (colDef.field === "age" || colDef.field === "athlete") {
          colDef.hide = true;
        }
      });
      gridApi.value!.setGridOption("columnDefs", columnDefs);
    }
    function onBtShow() {
      const columnDefs: ColDef[] = getColumnDefs();
      columnDefs.forEach((colDef) => {
        colDef.hide = false;
      });
      gridApi.value!.setGridOption("columnDefs", columnDefs);
    }
    function onBtPivotOn() {
      gridApi.value!.setGridOption("pivotMode", true);
      const columnDefs: ColDef[] = getColumnDefs();
      columnDefs.forEach((colDef) => {
        if (colDef.field === "country") {
          colDef.pivot = true;
        }
      });
      gridApi.value!.setGridOption("columnDefs", columnDefs);
    }
    function onBtPivotOff() {
      gridApi.value!.setGridOption("pivotMode", false);
      const columnDefs: ColDef[] = getColumnDefs();
      columnDefs.forEach((colDef) => {
        colDef.pivot = false;
      });
      gridApi.value!.setGridOption("columnDefs", columnDefs);
    }
    function onBtRowGroupOn() {
      const columnDefs: ColDef[] = getColumnDefs();
      columnDefs.forEach((colDef) => {
        if (colDef.field === "sport") {
          colDef.rowGroup = true;
        }
      });
      gridApi.value!.setGridOption("columnDefs", columnDefs);
    }
    function onBtRowGroupOff() {
      const columnDefs: ColDef[] = getColumnDefs();
      columnDefs.forEach((colDef) => {
        colDef.rowGroup = false;
      });
      gridApi.value!.setGridOption("columnDefs", columnDefs);
    }
    function onBtAggFuncOn() {
      const columnDefs: ColDef[] = getColumnDefs();
      columnDefs.forEach((colDef) => {
        if (
          colDef.field === "gold" ||
          colDef.field === "silver" ||
          colDef.field === "bronze"
        ) {
          colDef.aggFunc = "sum";
        }
      });
      gridApi.value!.setGridOption("columnDefs", columnDefs);
    }
    function onBtAggFuncOff() {
      const columnDefs: ColDef[] = getColumnDefs();
      columnDefs.forEach((colDef) => {
        colDef.aggFunc = null;
      });
      gridApi.value!.setGridOption("columnDefs", columnDefs);
    }
    function onBtPinnedOn() {
      const columnDefs: ColDef[] = getColumnDefs();
      columnDefs.forEach((colDef) => {
        if (colDef.field === "athlete") {
          colDef.pinned = "left";
        }
        if (colDef.field === "sport") {
          colDef.pinned = "right";
        }
      });
      gridApi.value!.setGridOption("columnDefs", columnDefs);
    }
    function onBtPinnedOff() {
      const columnDefs: ColDef[] = getColumnDefs();
      columnDefs.forEach((colDef) => {
        colDef.pinned = null;
      });
      gridApi.value!.setGridOption("columnDefs", columnDefs);
    }
    const onGridReady = (params: GridReadyEvent) => {
      gridApi.value = params.api;

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

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

    return {
      gridApi,
      defaultColDef,
      columnDefs,
      rowData,
      onGridReady,
      onSortChanged,
      onColumnResized,
      onColumnVisible,
      onColumnPivotChanged,
      onColumnRowGroupChanged,
      onColumnValueChanged,
      onColumnMoved,
      onColumnPinned,
      onBtSortOn,
      onBtSortOff,
      onBtWidthNarrow,
      onBtWidthNormal,
      onBtHide,
      onBtShow,
      onBtPivotOn,
      onBtPivotOff,
      onBtRowGroupOn,
      onBtRowGroupOff,
      onBtAggFuncOn,
      onBtAggFuncOff,
      onBtPinnedOn,
      onBtPinnedOff,
    };
  },
});

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

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

## Column Definition Retrieval

There will be times where you'll want to retrieve the current Column Definition in order to perhaps persist them, or perhaps retrieve, alter and then re-apply the modified columns.

The current column definitions can be retrieved with `getColumnDefs`:

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `getColumnDefs` | `Function` |  |  | Returns the current column definitions. Module: [`ColumnApiModule`](https://www.ag-grid.com/vue-data-grid/modules/). |

## Column Groups

Column Groups can be updated in the same way as Columns, you just update the Column Group Definition. For expandable groups, to have open / closed state to be maintained, you need to assign `groupId` in the Column Group Definition.

```ts
<ag-grid-vue
    :columnDefs="columnDefs"
    /* other grid options ... */>
</ag-grid-vue>

this.columnDefs = [
    {
        headerName: 'Group A',
        groupId: 'groupA',
        children: [
            { field: 'name' },
            { field: 'age', columnGroupShow: 'open' }
        ]
    }
];
```

In the example below, note the following:

1. Clicking the top buttons alternates the columns from two sets of definitions.
2. Column Group A - `groupId` is provided, so expand / collapse is preserved. The Header Name also changes.
3. Column Group B - `groupId` is NOT provided, so expand / collapse is lost, group always closes when updates happen.
4. Column Group C - `groupId` is provided, so expand / collapse is preserved. Child columns are changed.

#### Column Groups

```ts
import {
  createApp,
  defineComponent,
  onBeforeMount,
  ref,
  shallowRef,
} from "vue";
import { AgGridVue } from "ag-grid-vue3";
import "./styles.css";
import {
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  GridApi,
  GridOptions,
  GridReadyEvent,
  ModuleRegistry,
  enableDevValidations,
} from "ag-grid-community";
import { IOlympicData } from "./interfaces";
if (process.env.NODE_ENV !== "production") {
  enableDevValidations();
}

ModuleRegistry.registerModules([ClientSideRowModelModule]);

function createColSetA(): ColGroupDef[] {
  return [
    {
      headerName: "Group A",
      groupId: "groupA",
      children: [
        { field: "athlete" },
        { field: "age" },
        { field: "country", columnGroupShow: "open" },
      ],
    },
    {
      headerName: "Group B",
      children: [
        { field: "sport" },
        { field: "year" },
        { field: "date", columnGroupShow: "open" },
      ],
    },
    {
      headerName: "Group C",
      groupId: "groupC",
      children: [
        { field: "total" },
        { field: "gold", columnGroupShow: "open" },
        { field: "silver", columnGroupShow: "open" },
        { field: "bronze", columnGroupShow: "open" },
      ],
    },
  ];
}

function createColSetB(): ColGroupDef[] {
  return [
    {
      headerName: "GROUP A",
      groupId: "groupA",
      children: [
        { field: "athlete" },
        { field: "age" },
        { field: "country", columnGroupShow: "open" },
      ],
    },
    {
      headerName: "Group B",
      children: [
        { field: "sport" },
        { field: "year" },
        { field: "date", columnGroupShow: "open" },
      ],
    },
    {
      headerName: "Group C",
      groupId: "groupC",
      children: [
        { field: "total" },
        { field: "gold", columnGroupShow: "open" },
        { field: "silver", columnGroupShow: "open" },
        { field: "bronze", columnGroupShow: "open" },
        { field: "extraA" },
        { field: "extraB", columnGroupShow: "open" },
      ],
    },
  ];
}

const VueExample = defineComponent({
  template: `
        <div style="height: 100%">
                <div class="test-container">
      <div class="test-header">
        <button v-on:click="onBtSetA()">First Column Set</button>
        <button v-on:click="onBtSetB()">Second Column Set</button>
      </div>
      <ag-grid-vue
        style="width: 100%; height: 100%;"
        class="test-grid"
        @grid-ready="onGridReady"
        :defaultColDef="defaultColDef"
        :columnDefs="columnDefs"
        :rowData="rowData"></ag-grid-vue>
      </div>
        </div>
    `,
  components: {
    "ag-grid-vue": AgGridVue,
  },
  setup(props) {
    const gridApi = shallowRef<GridApi<IOlympicData> | null>(null);
    const defaultColDef = ref<ColDef>({
      initialWidth: 100,
    });
    const columnDefs = ref<(ColDef | ColGroupDef)[]>([
      {
        headerName: "Group A",
        groupId: "groupA",
        children: [
          { field: "athlete" },
          { field: "age" },
          { field: "country", columnGroupShow: "open" },
        ],
      },
      {
        headerName: "Group B",
        children: [
          { field: "sport" },
          { field: "year" },
          { field: "date", columnGroupShow: "open" },
        ],
      },
      {
        headerName: "Group C",
        groupId: "groupC",
        children: [
          { field: "total" },
          { field: "gold", columnGroupShow: "open" },
          { field: "silver", columnGroupShow: "open" },
          { field: "bronze", columnGroupShow: "open" },
        ],
      },
    ]);
    const rowData = ref<IOlympicData[]>(null);

    function onBtSetA() {
      gridApi.value!.setGridOption("columnDefs", createColSetA());
    }
    function onBtSetB() {
      gridApi.value!.setGridOption("columnDefs", createColSetB());
    }
    const onGridReady = (params: GridReadyEvent) => {
      gridApi.value = params.api;

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

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

    return {
      gridApi,
      defaultColDef,
      columnDefs,
      rowData,
      onGridReady,
      onBtSetA,
      onBtSetB,
    };
  },
});

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

[Live example: Column Groups](https://www.ag-grid.com/examples/column-updating-definitions/column-groups/vue3)
