DataGrid data operations

Data Operations

Coordinate sorting, filtering, and paging with one DataGrid state object.

Use local operations when the full array is already in the browser. Use manual operations when the server owns the data and the app needs a single event to request the next processed result.

Local data operations

The grid receives the full dataset through [data]. Sorting, filtering, and paging are processed internally, and (dataStateChange) reports the current combined state for analytics, URL sync, or state persistence.

Loading interactive DataGrid example…

Current local state

{
  "page": 1,
  "pageIndex": 0,
  "skip": 0,
  "pageSize": 5,
  "sort": [],
  "filter": {
    "logic": "and",
    "filters": []
  },
  "globalFilter": ""
}

Aggregate results

Aggregates use the same operation helper as the grid. They are calculated after filtering and sorting, but before paging, so totals represent the full current result set instead of only the visible page.

Records
42
Total value
$150,318
Average order
$3,579
Largest order
$6,408

Local code snippet

      @Component({
  imports: [Datagrid],
  template: `
    <ngb-datagrid
      [columns]="columns"
      [data]="orders"
      [enableSorting]="true"
      [filterable]="'row'"
      [dataOperations]="true"
      [pageable]="{ pageSizes: [5, 10], info: true }"
      [pageSize]="5"
      (dataStateChange)="state = $event"
    />
  `,
})
export class LocalOperationsDemo {
  state: NgbDataGridState | null = null;

  get result() {
    return ngbApplyDataGridOperations(this.orders, {
      columns: this.columns,
      state: this.state,
      aggregates: [
        { field: 'total', aggregate: 'sum' },
        { field: 'total', aggregate: 'average' },
        { field: 'id', aggregate: 'count' },
      ],
    });
  }
}
    

Manual/server-side data operations

The app handles (dataStateChange), sends that state to an API, then passes the returned page through [data] and the full result count through [total]. This lab uses an in-memory mock API to keep the example deterministic.

Manual modeShowing 0 of 0 records

Loading interactive DataGrid example…

Current manual state

{
  "page": 1,
  "pageIndex": 0,
  "skip": 0,
  "pageSize": 5,
  "sort": [],
  "filter": {
    "logic": "and",
    "filters": []
  },
  "globalFilter": ""
}

Manual code snippet

      @Component({
  imports: [Datagrid],
  template: `
    <ngb-datagrid
      [columns]="columns"
      [data]="rows"
      [total]="total"
      [loading]="loading"
      [state]="state"
      [enableSorting]="true"
      [filterable]="'row'"
      [filterManual]="true"
      [pageable]="{ pageSizes: [5, 10], info: true }"
      (dataStateChange)="loadPage($event)"
    />
  `,
})
export class ManualOperationsDemo {
  state: NgbDataGridState = { page: 1, pageSize: 5, sort: [], filter: { logic: 'and', filters: [] } };
  rows: Order[] = [];
  total = 0;
  loading = false;

  loadPage(state: NgbDataGridState): void {
    this.state = state;
    this.loading = true;
    this.ordersApi.query(state).subscribe((result) => {
      this.rows = result.data;
      this.total = result.total;
      this.loading = false;
    });
  }
}
    

API information

APITypeUsage
[state]NgbDataGridState | nullOptional controlled state for page, page size, skip, sort, filter, and global filter.
[dataOperations]boolean | NgbDataGridProcessOptionsOpts local arrays into the reusable helper pipeline for filter, sort, and page processing.
(dataStateChange)EventEmitter<NgbDataGridState>Emits the complete data-operation state after sort, filter, or page changes.
ngbApplyDataGridOperations(data, options) => NgbDataGridDataResultReusable helper that returns processed rows, total count, and optional aggregate results.
ngbCalculateDataGridAggregates(data, descriptors) => NgbDataGridAggregateResultsReusable helper for count, sum, average, min, and max aggregate values.
(sortChange){ active: string | null; direction: 'asc' | 'desc' | '' }Existing focused sort event, preserved for backward compatibility.
(filterChange)NgbCompositeFilterDescriptorExisting focused filter event, preserved for backward compatibility.
(pageChange){ page: number; pageSize: number }Existing focused page event, preserved for backward compatibility.
[total]number | nullFull server-side result count when the grid receives only the current page.
[filterManual]booleanSkips client-side filter processing when the host app/server owns filtering.

Usage notes and limitations

  • Use one state object to keep sorting, filtering, paging, and search in sync.
  • Grouping now uses the same unified state shape through state.group.
  • Enable local data operations when the browser already has the full dataset.
  • Use the standalone operation helper when you need to process data before passing it to the grid.
  • Aggregate values are calculated from the current filtered result, not just the visible page.
  • For server-backed grids, return the current rows plus the full total record count.
  • Use individual sort, filter, and page events when a screen only needs one specific change.

This project is not affiliated with ng-bootstrap or ngx-bootstrap. Those projects focus mainly on Bootstrap components for Angular. ngbootstrap focuses on Angular UI for data-heavy apps, especially Data Grid, Angular-native Form Builder, drag and drop workflows, documentation examples, and performance-focused Angular patterns.