@agility-workbench/angular-grid
Angular bindings for @agility-workbench/grid —
a high-performance data grid. Provides the standalone <awb-grid> component and re-exports the
full core API, so you can import everything you need from one place. Supports Angular 20.3
through 22 (zone-based and zoneless applications) on Node 20.19+.
What each release added is on the documentation site's changelog.
Installation
npm install @agility-workbench/angular-grid
@agility-workbench/grid is installed automatically as a dependency; @angular/core (20.3–22,
each major verified against the packed artifact) is a peer dependency your app provides.
Quick start
import { Component } from "@angular/core";
import {
AwbGrid,
ColumnType,
type IGridAPI,
type NgColDef,
} from "@agility-workbench/angular-grid";
@Component({
selector: "app-example",
standalone: true,
imports: [AwbGrid],
template: `
<div style="height: 400px">
<awb-grid
[rowData]="rowData"
[columnDefs]="columnDefs"
rowIdKey="id"
[rowNumbers]="true"
(gridReady)="onGridReady($event)"
/>
</div>
`,
})
export class ExampleComponent {
columnDefs: NgColDef[] = [
{ key: "name", label: "Name", type: ColumnType.STRING },
{ key: "price", label: "Price", type: ColumnType.NUMBER },
];
rowData = [
{ id: "1", name: "Widget", price: 9.99 },
{ id: "2", name: "Gadget", price: 14.5 },
];
onGridReady(api: IGridAPI): void {
// Imperative API: sorting, selection, editing, exports, view state, …
}
}
The grid fills its host element — give <awb-grid> (or a wrapper) a height. The component is
also available via template reference: <awb-grid #grid="awbGrid" /> → grid.api.
[quickFilter] is a live input — the global search over every visible column. It filters rows by
default, or behavior: "find" leaves every row in place and highlights matching cells instead, with
a match counter, Enter / Shift+Enter stepping, and showBehaviorToggle to let the end user
switch; the (quickFilterFindChanged) output reports the match count and the active match. See the
core README for the match modes and what find can search.
Grid options are signal inputs, including pivot mode and sheets: [pivotMode] /
[pivotColumns] are live (synced through the imperative API, so values assigned in gridReady
are not overwritten), [pivotColumnMoveMode] is live, [pivotResultColumnDef] /
[maxPivotColumns] / [pivotNoValuesMessage] / [pivotEmptyMessage] are creation-time, and
[sheets] renders the footer tab strip with the same app-owned persistence contract as
[savedViews]. See the core README for what pivot mode and sheets do.
Most inputs are live. The ones the grid reads only at creation (rowHeight, getRowId,
rowIdKey, rowModelType, defaultColDef, groupColumnDef, pivotResultColumnDef,
initialSort, … — the core's CREATION_ONLY_OPTION_KEYS, minus the bridged inputs) ignore later
changes; in development mode (isDevMode()) the grid logs one console.warn naming the input when
that happens. Re-create the <awb-grid> (for example under an @if, or a keyed @for) to apply
such a change. The Angular page of the documentation site has the full live-vs-creation table.
Outputs: (gridReady), (cellClicked), (rowClicked), (cellDoubleClicked),
(rowDoubleClicked), (cellValueChanged), (selectionChanged), (sortChanged),
(filterChanged), (quickFilterFindChanged), (historyChanged), (columnsChanged),
(paginationChanged) and (gridError) (the core error event — not (error), which Angular
would also bind as a native DOM listener on the host). (columnsChanged) and (sortChanged)
carry source: "user" | "api"; persist column state on "user" so restoring it never echoes
back. Anything else: api.on(eventName, handler).
Styling
Nothing to do — the grid delivers its own stylesheet when it attaches, once per document, and once per shadow root for grids inside one.
Under a strict Content Security Policy without style-src 'unsafe-inline', pass a nonce via the
styleNonce input (page-global, so use the same value for every grid). To load the stylesheet
yourself instead — via angular.json styles or a global import of
@agility-workbench/grid/styles.css — set suppressStyleInjection on each grid, so the two
copies do not fight in the cascade.
Angular components in the grid
Column definitions accept Angular component classes wherever the core accepts a class component —
cellRenderer, cellEditor, tooltipComponent, headerTooltip, actionFrameComponent, the
set-filter components in filterParams, and the header components headerComponent (header
content) and headerCellComponent (the whole header cell; contract IHeaderNgComp). The same slots
are adapted in [defaultColDef], [groupColumnDef], and [pivotResultColumnDef]. A component
receives its params either through an input named params or by implementing
awbInit(params) (plus optional awbRefresh(params)):
import { Component, input } from "@angular/core";
import type { CellRendererParams } from "@agility-workbench/angular-grid";
@Component({
standalone: true,
template: `<strong>{{ params()?.value }}</strong>`,
})
export class BoldCell {
readonly params = input<CellRendererParams>();
}
const columnDefs: NgColDef[] = [{ key: "name", label: "Name", cellRenderer: BoldCell }];
Cell editors implement ICellEditorNgComp (getValue() plus optional focus, isParsed,
isCancelBeforeStart). Menu items returned from getColumnMenuItems / bodyContextMenu /
multiColumnMenu may use TemplateRefs for their left/right slots (NgMenuItem).