State Persistence
The grid's whole UI state — sorting, filters, grouping, column widths, order, pins and visibility — is one serializable snapshot. Persist it automatically with stateKey (localStorage by default, any sync or async backend via OGE_STATE_STORAGE), or take full control with state() / applyState() and the stateChange event.
Sort, filter, group, resize or hide columns — then reload the page: everything comes back.
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { OgeColumn, OgeGrid } from '@oge-ui/grid';
@Component({
selector: 'demo-root',
imports: [OgeColumn, OgeGrid],
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<!-- everything the user changes — sort, filters, grouping, column
widths/order/pins/visibility — is saved under this key and restored
on the next visit. Default backend: localStorage. -->
<oge-grid [data]="employees" keyField="id" stateKey="orders-grid"
[groupPanel]="true" [filterRow]="true" [columnChooser]="true">
<oge-column field="firstName" />
<oge-column field="department" />
<oge-column field="salary" dataType="number" />
</oge-grid>
`,
})
export class Demo {
readonly employees = [
{ id: 1, firstName: 'Ali', lastName: 'Yılmaz', department: 'Engineering', city: 'İstanbul', salary: 8400, hireDate: '2019-03-11' },
{ id: 2, firstName: 'Ayşe', lastName: 'Kaya', department: 'Sales', city: 'Ankara', salary: 7200, hireDate: '2020-07-02' },
{ id: 3, firstName: 'Mehmet', lastName: 'Demir', department: 'Engineering', city: 'İzmir', salary: 9100, hireDate: '2018-01-23' },
{ id: 4, firstName: 'Zeynep', lastName: 'Şahin', department: 'Finance', city: 'İstanbul', salary: 6800, hireDate: '2021-11-15' },
{ id: 5, firstName: 'Emre', lastName: 'Çelik', department: 'Support', city: 'Bursa', salary: 5400, hireDate: '2022-05-09' },
];
}Custom backend (API, database, IndexedDB…)
Provide OGE_STATE_STORAGE anywhere in the injector tree — both methods may return promises, so an HTTP backend plugs in directly. The demo below saves through a fake API with 250ms latency; watch the calls on the right.
Fake API log (250ms latency)
- Sort or filter the grid…
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { OgeColumn, OgeGrid, OGE_STATE_STORAGE } from '@oge-ui/grid';
import { HttpClient } from '@angular/common/http';
import { firstValueFrom } from 'rxjs';
import type { ApplicationConfig } from '@angular/core';
import type { OgeStateStorage } from '@oge-ui/grid';
@Component({
selector: 'demo-root',
imports: [OgeColumn, OgeGrid],
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<oge-grid [data]="employees" keyField="id" stateKey="orders-grid">
<oge-column field="firstName" />
</oge-grid>
`,
})
export class Demo {
readonly employees = [
{ id: 1, firstName: 'Ali', lastName: 'Yılmaz', department: 'Engineering', city: 'İstanbul', salary: 8400, hireDate: '2019-03-11' },
{ id: 2, firstName: 'Ayşe', lastName: 'Kaya', department: 'Sales', city: 'Ankara', salary: 7200, hireDate: '2020-07-02' },
{ id: 3, firstName: 'Mehmet', lastName: 'Demir', department: 'Engineering', city: 'İzmir', salary: 9100, hireDate: '2018-01-23' },
{ id: 4, firstName: 'Zeynep', lastName: 'Şahin', department: 'Finance', city: 'İstanbul', salary: 6800, hireDate: '2021-11-15' },
{ id: 5, firstName: 'Emre', lastName: 'Çelik', department: 'Support', city: 'Bursa', salary: 5400, hireDate: '2022-05-09' },
];
}
// Persist wherever you want — the backend may be fully async.
export function provideRemoteGridState(http: HttpClient): ApplicationConfig {
return {
providers: [
{
provide: OGE_STATE_STORAGE,
useValue: {
get: (key: string) =>
firstValueFrom(
http.get(`/api/grid-state/${key}`, { responseType: 'text' }),
),
set: (key: string, value: string) =>
firstValueFrom(http.put(`/api/grid-state/${key}`, value)).then(
() => undefined,
),
} satisfies OgeStateStorage,
},
],
};
}Imperative: state() / applyState() / stateChange
No token needed: read the snapshot with state(), apply one with applyState(), and react to stateChange (debounced) to persist on your own terms — e.g. a Save view button or per-user server profiles.
Last stateChange payload
—
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { OgeColumn, OgeGrid } from '@oge-ui/grid';
import type { GridStateSnapshot } from '@oge-ui/core';
@Component({
selector: 'demo-root',
imports: [OgeColumn, OgeGrid],
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<!-- full control, no token needed -->
<oge-grid #grid [data]="employees" keyField="id"
(stateChange)="saveToBackend($event)">
<oge-column field="firstName" />
</oge-grid>
<button type="button" (click)="capture(grid.state())">Capture</button>
`,
})
export class Demo {
readonly employees = [
{ id: 1, firstName: 'Ali', lastName: 'Yılmaz', department: 'Engineering', city: 'İstanbul', salary: 8400, hireDate: '2019-03-11' },
{ id: 2, firstName: 'Ayşe', lastName: 'Kaya', department: 'Sales', city: 'Ankara', salary: 7200, hireDate: '2020-07-02' },
{ id: 3, firstName: 'Mehmet', lastName: 'Demir', department: 'Engineering', city: 'İzmir', salary: 9100, hireDate: '2018-01-23' },
{ id: 4, firstName: 'Zeynep', lastName: 'Şahin', department: 'Finance', city: 'İstanbul', salary: 6800, hireDate: '2021-11-15' },
{ id: 5, firstName: 'Emre', lastName: 'Çelik', department: 'Support', city: 'Bursa', salary: 5400, hireDate: '2022-05-09' },
];
private snapshot: GridStateSnapshot | null = null;
// capture / restore programmatically — the snapshot is serializable
protected capture(snapshot: GridStateSnapshot): void {
this.snapshot = snapshot;
}
// stateChange fires debounced on every user-driven change
protected saveToBackend(snapshot: GridStateSnapshot): void {
void fetch('/api/me/grid-state', {
method: 'PUT',
body: JSON.stringify(snapshot),
});
}
}Notes
- The snapshot is plain JSON (
GridStateSnapshotfrom@oge-ui/core) — safe to store, diff, and version. - Saves are debounced (250ms), so rapid interactions produce one write.
- Restore is async-aware: with an API backend the grid renders immediately and applies the state when it arrives — unless the user already navigated to another
stateKey. applyState()also works across grids: capture on one, apply to another with the same columns.