---
title: "Grid Lifecycle"
framework: angular
version: "36.1.0"
---

# Grid Lifecycle

This section covers some common lifecycle events that are raised after grid initialisation, data updates, and before the grid is destroyed.

> **Note**
>
> The events on this page are listed in the order they are raised.

## Grid Ready

The `gridReady` event fires upon grid initialisation but the grid may not be fully rendered.

**Common Uses**

- Customising Grid via API calls.
- Event listener setup.
- Grid-dependent setup code.

In this example, `gridReady` applies user pinning preferences before rendering data.

#### Using Grid Ready Event

```ts
import { Component } from "@angular/core";

import { AgGridAngular } from "ag-grid-angular";
import type { ColDef, GridApi, GridReadyEvent } from "ag-grid-community";
import {
  ClientSideRowModelModule,
  ColumnApiModule,
  ModuleRegistry,
  enableDevValidations,
} from "ag-grid-community";

import { getData } from "./data";
import "./styles.css";

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

ModuleRegistry.registerModules([ColumnApiModule, ClientSideRowModelModule]);

@Component({
  standalone: true,
  imports: [AgGridAngular],
  selector: "my-app",
  template: `
    <div class="test-container">
      <div class="test-header">
        <div style="margin-bottom: 1rem;">
          <input type="checkbox" id="pinFirstColumnOnLoad" />
          <label for="pinFirstColumnOnLoad">Pin first column on load</label>
        </div>
        <div style="margin-bottom: 1rem;">
          <button id="reloadGridButton" (click)="reloadGrid()">
            Reload Grid
          </button>
        </div>
      </div>
      @if (isVisible) {
        <ag-grid-angular
          style="width: 100%; height: 100%;"
          [columnDefs]="columnDefs"
          [rowData]="rowData"
          (gridReady)="onGridReady($event)"
        />
      }
    </div>
  `,
})
export class AppComponent {
  public isVisible = true;
  private gridApi!: GridApi;
  public columnDefs: ColDef[] = [
    { field: "name", headerName: "Athlete", width: 250 },
    { field: "person.country", headerName: "Country" },
    { field: "person.age", headerName: "Age" },
    { field: "medals.gold", headerName: "Gold Medals" },
    { field: "medals.silver", headerName: "Silver Medals" },
    { field: "medals.bronze", headerName: "Bronze Medals" },
  ];

  public rowData: any[] | null = getData();

  reloadGrid() {
    this.isVisible = false;
    setTimeout(() => (this.isVisible = true), 1);
  }

  onGridReady(params: GridReadyEvent) {
    this.gridApi = params.api;
    const checkbox = document.querySelector<HTMLInputElement>(
      "#pinFirstColumnOnLoad",
    )!;
    const shouldPinFirstColumn = checkbox && checkbox.checked;
    if (shouldPinFirstColumn) {
      params.api.applyColumnState({
        state: [{ colId: "name", pinned: "left" }],
      });
    }
  }
}
```

[Live example: Using Grid Ready Event](https://www.ag-grid.com/examples/grid-lifecycle/grid-ready/angular)

## First Data Rendered

The `firstDataRendered` event fires the first time data is rendered into the grid. It will only be fired once unlike `rowDataUpdated` which is fired on every data change.

## Row Data Updated

The `rowDataUpdated` event fires every time the grid's data changes, by [Updating Row Data](https://www.ag-grid.com/angular-data-grid/data-update-row-data/) or by applying [Transaction Updates](https://www.ag-grid.com/angular-data-grid/data-update-transactions/). In the [Server Side Row Model](https://www.ag-grid.com/angular-data-grid/server-side-model/), use the [Model Updated Event](https://www.ag-grid.com/angular-data-grid/grid-events/#reference-gridLifecycle-modelUpdated) instead.

In this example the time at which `firstDataRendered` and `rowDataUpdated` are fired is recorded above the grid. Note that `firstDataRendered` is only set on the initial load of the grid and is not updated when reloading data.

#### Using Row Data Event

```ts
import { Component } from "@angular/core";
import { AgGridAngular } from "ag-grid-angular";
import "./styles.css";
import {
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  FirstDataRenderedEvent,
  GridApi,
  GridOptions,
  GridReadyEvent,
  ModuleRegistry,
  RowDataUpdatedEvent,
  enableDevValidations,
} from "ag-grid-community";
import { TAthlete, fetchDataAsync } from "./data";
if (process.env.NODE_ENV !== "production") {
  enableDevValidations();
}

ModuleRegistry.registerModules([ClientSideRowModelModule]);

@Component({
  selector: "my-app",
  standalone: true,
  imports: [AgGridAngular],
  template: `<div class="test-container">
    <div class="test-header">
      <div id="firstDataRendered">
        First Data Rendered: <span class="value">-</span>
      </div>
      <div id="rowDataUpdated">
        Row Data Updated: <span class="value">-</span>
      </div>
      <div>
        <button id="btnReloadData" (click)="onBtnReloadData()">
          Reload Data
        </button>
      </div>
    </div>
    <ag-grid-angular
      style="width: 100%; height: 100%;"
      [columnDefs]="columnDefs"
      [loading]="true"
      [rowData]="rowData"
      (firstDataRendered)="onFirstDataRendered($event)"
      (rowDataUpdated)="onRowDataUpdated($event)"
      (gridReady)="onGridReady($event)"
    />
  </div> `,
})
export class AppComponent {
  private gridApi!: GridApi;

  columnDefs: ColDef[] = [
    { field: "name", headerName: "Athlete" },
    { field: "person.age", headerName: "Age" },
    { field: "medals.gold", headerName: "Gold Medals" },
  ];
  rowData!: any[];

  onFirstDataRendered(event: FirstDataRenderedEvent) {
    updateRowCount("firstDataRendered");
    console.log("First Data Rendered");
  }

  onRowDataUpdated(event: RowDataUpdatedEvent<TAthlete>) {
    updateRowCount("rowDataUpdated");
    console.log("Row Data Updated");
  }

  onBtnReloadData() {
    console.log("Reloading Data ...");
    setBtnReloadDataDisabled(true);
    this.gridApi.setGridOption("loading", true);
    fetchDataAsync()
      .then((data) => {
        console.log("Data Reloaded");
        this.gridApi.setGridOption("rowData", data);
      })
      .catch((error) => {
        console.error("Failed to reload data", error);
      })
      .finally(() => {
        this.gridApi.setGridOption("loading", false);
        setBtnReloadDataDisabled(false);
      });
  }

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

    console.log("Loading Data ...");
    fetchDataAsync()
      .then((data) => {
        console.log("Data Loaded");
        params.api!.setGridOption("rowData", data);
      })
      .catch((error) => {
        console.error("Failed to load data", error);
      })
      .finally(() => {
        params.api!.setGridOption("loading", false);
        setBtnReloadDataDisabled(false);
      });
  }
}

const updateRowCount = (id: string) => {
  const element = document.querySelector(`#${id} > .value`);
  element!.textContent = `${new Date().toLocaleTimeString()}`;
};
const setBtnReloadDataDisabled = (disabled: boolean) => {
  (document.getElementById("btnReloadData") as HTMLButtonElement).disabled =
    disabled;
};
```

[Live example: Using Row Data Event](https://www.ag-grid.com/examples/grid-lifecycle/row-data-updated/angular)

## Grid Pre-Destroyed

The `gridPreDestroyed` event fires just before the grid is destroyed and is removed from the DOM.

**Common Uses**

- Clean up resources.
- Save grid state.
- Disconnect other libraries.

The [Grid State Example](https://www.ag-grid.com/angular-data-grid/grid-state/#saving-and-restoring-state) demonstrates how `gridPreDestroyed` can be used to save and restore grid state.

### Angular PreDestroy Setup

When using Angular, the `gridPreDestroyed` event handler must be registered via grid options instead of as an Output event handler to work correctly.

For example:

```js
this.gridOptions = {
    onGridPreDestroyed: () => {
        // handler code
    }
};
```
