---
title: "SSRM Refresh"
enterprise: true
framework: angular
version: "36.1.0"
---

# SSRM Refresh

This section demonstrates refreshing rows in order to reflect changes at the source while using the Server-Side Row Model (SSRM).

> **Note**
>
> It is advised to use [Row IDs](https://www.ag-grid.com/angular-data-grid/server-side-model-configuration/#providing-row-ids) when using Server-Side Refresh. Row IDs allow the grid to retain row state between refreshes, such as row height, expanded state, and cell flashing.

## Refresh API

The grid API `refreshServerSide(params)` instructs the grid to start reloading all loaded rows for a specified group.

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `refreshServerSide` | `Function` |  |  | Refresh a server-side store level. If you pass no parameters, then the top level store is refreshed. To refresh a child level, pass in the string of keys to get to the desired level. Once the store refresh is complete, the storeRefreshed event is fired. Module: [`ServerSideRowModelApiModule`](https://www.ag-grid.com/angular-data-grid/modules/). |

## Simple Example

To ensure your grid reflects the latest data on your server, you can periodically instruct the grid to refresh all of the loaded rows (known as polling) or strategically refresh based on your applications requirements.

The following example provides a simple demonstration of the different behaviours of the refresh API, note the following:

- Using the **Refresh Rows** button, you can request that all the rows are requested from the server again, bringing them up to date with the server version.
- Because [Row IDs](https://www.ag-grid.com/angular-data-grid/server-side-model-configuration/#providing-row-ids) have been implemented, the grid is able to detect which rows have been updated, and flash cells when using `enableCellChangeFlash`.
- The `Purge` checkbox enables the purge option in the API call, this causes all rows (and all row state except row selection state) to be reset when the refresh call is made, and replaced with loading rows.
- When a refresh is finished, note the `storeRefreshed` event is fired, and logged in the console. This is not fired when the purge option is enabled as the rows are reset not refreshed.

#### Simple Example

```ts
import { Component } from "@angular/core";
import { HttpClient } from "@angular/common/http";
import { AgGridAngular } from "ag-grid-angular";
import "./styles.css";
import {
  AutoGroupColumnDef,
  ColDef,
  ColGroupDef,
  GetRowIdFunc,
  GetRowIdParams,
  GridApi,
  GridOptions,
  GridReadyEvent,
  HighlightChangesModule,
  IServerSideDatasource,
  ModuleRegistry,
  RowModelType,
  StoreRefreshedEvent,
  enableDevValidations,
} from "ag-grid-community";
import {
  RowGroupingModule,
  ServerSideRowModelApiModule,
  ServerSideRowModelModule,
} from "ag-grid-enterprise";
import { FakeServer } from "./fakeServer";
if (process.env.NODE_ENV !== "production") {
  enableDevValidations();
}

ModuleRegistry.registerModules([
  HighlightChangesModule,
  RowGroupingModule,
  ServerSideRowModelModule,
  ServerSideRowModelApiModule,
]);

@Component({
  selector: "my-app",
  standalone: true,
  imports: [AgGridAngular],
  template: `<div class="example-wrapper">
    <div style="margin-bottom: 5px">
      <div>Version on server: <span id="version-indicator">1</span></div>
      <button (click)="refreshCache(undefined)">Refresh Rows</button>

      <label><input type="checkbox" id="purge" /> Purge</label>
    </div>
    <ag-grid-angular
      style="width: 100%; height: 100%;"
      [columnDefs]="columnDefs"
      [defaultColDef]="defaultColDef"
      [autoGroupColumnDef]="autoGroupColumnDef"
      [getRowId]="getRowId"
      [rowModelType]="rowModelType"
      [suppressAggFuncInHeader]="true"
      [rowData]="rowData"
      (storeRefreshed)="onStoreRefreshed($event)"
      (gridReady)="onGridReady($event)"
    />
  </div> `,
})
export class AppComponent {
  private gridApi!: GridApi;

  columnDefs: ColDef[] = [
    { field: "country" },
    { field: "year" },
    { field: "version" },
    { field: "gold", aggFunc: "sum" },
    { field: "silver", aggFunc: "sum" },
    { field: "bronze", aggFunc: "sum" },
  ];
  defaultColDef: ColDef = {
    flex: 1,
    minWidth: 150,
    enableCellChangeFlash: true,
  };
  autoGroupColumnDef: AutoGroupColumnDef = {
    flex: 1,
    minWidth: 280,
    field: "athlete",
  };
  getRowId: GetRowIdFunc = (params: GetRowIdParams) => {
    const data = params.data;
    const parts = [];
    if (data.country != null) {
      parts.push(data.country);
    }
    if (data.year != null) {
      parts.push(data.year);
    }
    if (data.id != null) {
      parts.push(data.id);
    }
    return parts.join("-");
  };
  rowModelType: RowModelType = "serverSide";
  rowData!: any[];

  constructor(private http: HttpClient) {}

  onStoreRefreshed(event: StoreRefreshedEvent) {
    console.log("Refresh finished for store with route:", event.route);
  }

  refreshCache(route?: string[]) {
    const purge = !!(document.querySelector("#purge") as HTMLInputElement)
      .checked;
    this.gridApi.refreshServerSide({ route: route, purge: purge });
  }

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

    this.http
      .get<any[]>("https://www.ag-grid.com/example-assets/olympic-winners.json")
      .subscribe((data) => {
        // give each data item an ID
        const dataWithId = data.map((d: any, idx: number) => ({
          ...d,
          id: idx,
        }));
        allData = dataWithId;
        // setup the fake server with entire dataset
        const fakeServer = new FakeServer(allData);
        // create datasource with a reference to the fake server
        const datasource = getServerSideDatasource(fakeServer);
        // register the datasource with the grid
        params.api!.setGridOption("serverSideDatasource", datasource);
        beginPeriodicallyModifyingData();
      });
  }
}

let allData: any[];
let versionCounter = 1;
const updateChangeIndicator = () => {
  const el = document.querySelector("#version-indicator") as HTMLInputElement;
  el.textContent = `${versionCounter}`;
};
const beginPeriodicallyModifyingData = () => {
  setInterval(() => {
    versionCounter += 1;
    allData = allData.map((data) => ({
      ...data,
      version: versionCounter + " - " + versionCounter + " - " + versionCounter,
    }));
    updateChangeIndicator();
  }, 4000);
};
const getServerSideDatasource = (server: any): IServerSideDatasource => {
  return {
    getRows: (params) => {
      console.log("[Datasource] - rows requested by grid: ", params.request);
      const response = server.getData(params.request);
      const dataWithVersionAndGroupProperties = response.rows.map(
        (rowData: any) => {
          const rowProperties: any = {
            ...rowData,
            version:
              versionCounter + " - " + versionCounter + " - " + versionCounter,
          };
          // for unique-id purposes in the client, we also want to attach
          // the parent group keys
          const groupProperties = Object.fromEntries(
            params.request.groupKeys.map((groupKey, index) => {
              const col = params.request.rowGroupCols[index];
              const field = col.id;
              return [field, groupKey];
            }),
          );
          return {
            ...rowProperties,
            ...groupProperties,
          };
        },
      );
      // adding delay to simulate real server call
      setTimeout(() => {
        if (response.success) {
          // call the success callback
          params.success({
            rowData: dataWithVersionAndGroupProperties,
            rowCount: response.lastRow,
          });
        } else {
          // inform the grid request failed
          params.fail();
        }
      }, 1000);
    },
  };
};
```

[Live example: Simple Example](https://www.ag-grid.com/examples/server-side-model-updating-refresh/refreshing-the-grid/angular)

## Refreshing Groups

When using row grouping with refreshing you are required to provide a route parameter specifying the row group to refresh. When a row group is refreshed, only its direct child rows are refreshed. This means that in order to refresh the rows in a particular row group, you need to provide the parent of the rows to be refreshed as the route parameter.

The following example demonstrates how to refresh specified groups on the server, note the following:

- Using the **Refresh Root Level** button, you can force all the rows in the root level group to refresh, this is equivalent to omitting a route parameter from the `refreshServerSide` API call.
- The **Refresh ['Canada'] Group** button only refreshes the direct children of the `Canada` row group.
- The **Refresh ['Canada', '2002'] Group** button only refreshes the direct children of the `2002` row group that belongs to the `Canada` row group.
- Because [Row IDs](https://www.ag-grid.com/angular-data-grid/server-side-model-configuration/#providing-row-ids) have been implemented, the grid is able to retain the state for reloaded rows, such as whether a group row was expanded.
- When a refresh is finished, note the `storeRefreshed` event is fired, and logged in the console.

#### Refreshing Groups

```ts
import { Component } from "@angular/core";
import { HttpClient } from "@angular/common/http";
import { AgGridAngular } from "ag-grid-angular";
import "./styles.css";
import {
  AutoGroupColumnDef,
  ColDef,
  ColGroupDef,
  GetRowIdFunc,
  GetRowIdParams,
  GridApi,
  GridOptions,
  GridReadyEvent,
  HighlightChangesModule,
  IServerSideDatasource,
  IsServerSideGroupOpenByDefault,
  IsServerSideGroupOpenByDefaultParams,
  ModuleRegistry,
  RowModelType,
  StoreRefreshedEvent,
  enableDevValidations,
} from "ag-grid-community";
import {
  RowGroupingModule,
  ServerSideRowModelApiModule,
  ServerSideRowModelModule,
} from "ag-grid-enterprise";
import { FakeServer } from "./fakeServer";
if (process.env.NODE_ENV !== "production") {
  enableDevValidations();
}

ModuleRegistry.registerModules([
  HighlightChangesModule,
  RowGroupingModule,
  ServerSideRowModelModule,
  ServerSideRowModelApiModule,
]);

@Component({
  selector: "my-app",
  standalone: true,
  imports: [AgGridAngular],
  template: `<div class="example-wrapper">
    <div style="margin-bottom: 5px">
      <div>Version on server: <span id="version-indicator">1</span></div>
      <button (click)="refreshCache(undefined)">Refresh Root Level</button>
      <button (click)="refreshCache(['Canada'])">
        Refresh ['Canada'] Group
      </button>
      <button (click)="refreshCache(['Canada', '2002'])">
        Refresh ['Canada', '2002'] Group
      </button>

      <label><input type="checkbox" id="purge" /> Purge</label>
    </div>
    <ag-grid-angular
      style="width: 100%; height: 100%;"
      [columnDefs]="columnDefs"
      [defaultColDef]="defaultColDef"
      [autoGroupColumnDef]="autoGroupColumnDef"
      [getRowId]="getRowId"
      [isServerSideGroupOpenByDefault]="isServerSideGroupOpenByDefault"
      [rowModelType]="rowModelType"
      [suppressAggFuncInHeader]="true"
      [rowData]="rowData"
      (storeRefreshed)="onStoreRefreshed($event)"
      (gridReady)="onGridReady($event)"
    />
  </div> `,
})
export class AppComponent {
  private gridApi!: GridApi;

  columnDefs: ColDef[] = [
    { field: "country", hide: true, rowGroup: true },
    { field: "year", hide: true, rowGroup: true },
    { field: "version" },
    { field: "gold", aggFunc: "sum" },
    { field: "silver", aggFunc: "sum" },
    { field: "bronze", aggFunc: "sum" },
  ];
  defaultColDef: ColDef = {
    flex: 1,
    minWidth: 150,
    enableCellChangeFlash: true,
  };
  autoGroupColumnDef: AutoGroupColumnDef = {
    flex: 1,
    minWidth: 280,
    field: "athlete",
  };
  getRowId: GetRowIdFunc = (params: GetRowIdParams) => {
    const data = params.data;
    const parts = [];
    if (data.country != null) {
      parts.push(data.country);
    }
    if (data.year != null) {
      parts.push(data.year);
    }
    if (data.id != null) {
      parts.push(data.id);
    }
    return parts.join("-");
  };
  isServerSideGroupOpenByDefault: IsServerSideGroupOpenByDefault = (
    params: IsServerSideGroupOpenByDefaultParams,
  ) => {
    return (
      params.rowNode.key === "Canada" ||
      params.rowNode.key!.toString() === "2002"
    );
  };
  rowModelType: RowModelType = "serverSide";
  rowData!: any[];

  constructor(private http: HttpClient) {}

  onStoreRefreshed(event: StoreRefreshedEvent) {
    console.log("Refresh finished for store with route:", event.route);
  }

  refreshCache(route?: string[]) {
    const purge = !!(document.querySelector("#purge") as HTMLInputElement)
      .checked;
    this.gridApi.refreshServerSide({ route: route, purge: purge });
  }

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

    this.http
      .get<any[]>("https://www.ag-grid.com/example-assets/olympic-winners.json")
      .subscribe((data) => {
        // give each data item an ID
        const dataWithId = data.map((d: any, idx: number) => ({
          ...d,
          id: idx,
        }));
        allData = dataWithId;
        // setup the fake server with entire dataset
        const fakeServer = new FakeServer(allData);
        // create datasource with a reference to the fake server
        const datasource = getServerSideDatasource(fakeServer);
        // register the datasource with the grid
        params.api!.setGridOption("serverSideDatasource", datasource);
        beginPeriodicallyModifyingData();
      });
  }
}

let allData: any[];
let versionCounter = 1;
const updateChangeIndicator = () => {
  const el = document.querySelector("#version-indicator") as HTMLInputElement;
  el.textContent = `${versionCounter}`;
};
const beginPeriodicallyModifyingData = () => {
  setInterval(() => {
    versionCounter += 1;
    allData = allData.map((data) => ({
      ...data,
      version: versionCounter + " - " + versionCounter + " - " + versionCounter,
    }));
    updateChangeIndicator();
  }, 4000);
};
const getServerSideDatasource = (server: any): IServerSideDatasource => {
  return {
    getRows: (params) => {
      console.log("[Datasource] - rows requested by grid: ", params.request);
      const response = server.getData(params.request);
      const dataWithVersionAndGroupProperties = response.rows.map(
        (rowData: any) => {
          const rowProperties: any = {
            ...rowData,
            version:
              versionCounter + " - " + versionCounter + " - " + versionCounter,
          };
          // for unique-id purposes in the client, we also want to attach
          // the parent group keys
          const groupProperties = Object.fromEntries(
            params.request.groupKeys.map((groupKey, index) => {
              const col = params.request.rowGroupCols[index];
              const field = col.id;
              return [field, groupKey];
            }),
          );
          return {
            ...rowProperties,
            ...groupProperties,
          };
        },
      );
      // adding delay to simulate real server call
      setTimeout(() => {
        if (response.success) {
          // call the success callback
          params.success({
            rowData: dataWithVersionAndGroupProperties,
            rowCount: response.lastRow,
          });
        } else {
          // inform the grid request failed
          params.fail();
        }
      }, 1000);
    },
  };
};
```

[Live example: Refreshing Groups](https://www.ag-grid.com/examples/server-side-model-updating-refresh/refreshing-the-groups/angular)
