Angular Data Grid
ApexGrid is a Lit web component that works with Angular through the CUSTOM_ELEMENTS_SCHEMA or standalone component imports.
Installation
npm install apex-grid
Standalone component setup (Angular 15+, recommended)
Declare CUSTOM_ELEMENTS_SCHEMA on the component itself and register the element before first render.
// app.component.ts
import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'
import { ApexGrid, ColumnConfiguration } from 'apex-grid'
ApexGrid.register()
interface User {
id: number
name: string
email: string
role: string
}
@Component({
selector: 'app-root',
standalone: true,
schemas: [CUSTOM_ELEMENTS_SCHEMA],
template: `
<apex-grid
[data]="users"
[columns]="columns"
></apex-grid>
`
})
export class AppComponent {
users: User[] = [
{ id: 1, name: 'Alice', email: 'alice@example.com', role: 'Admin' },
{ id: 2, name: 'Bob', email: 'bob@example.com', role: 'Editor' },
]
columns: ColumnConfiguration<User>[] = [
{ key: 'id', headerText: 'ID', type: 'number' },
{ key: 'name', headerText: 'Name', sort: true, filter: true },
{ key: 'email', headerText: 'Email', sort: true },
{ key: 'role', headerText: 'Role', type: 'select',
options: ['Admin', 'Editor', 'Viewer'] },
]
}
NgModule setup (Angular 14 and earlier)
Add CUSTOM_ELEMENTS_SCHEMA to the schemas array of the root module, then register the element in the component file.
// app.module.ts
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { AppComponent } from './app.component'
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
bootstrap: [AppComponent]
})
export class AppModule {}
// app.component.ts
import { Component } from '@angular/core'
import { ApexGrid, ColumnConfiguration } from 'apex-grid'
ApexGrid.register()
interface User {
id: number
name: string
email: string
}
@Component({
selector: 'app-root',
template: `
<apex-grid
[data]="users"
[columns]="columns"
></apex-grid>
`
})
export class AppComponent {
users: User[] = [
{ id: 1, name: 'Alice', email: 'alice@example.com' },
{ id: 2, name: 'Bob', email: 'bob@example.com' },
]
columns: ColumnConfiguration<User>[] = [
{ key: 'id', headerText: 'ID', type: 'number' },
{ key: 'name', headerText: 'Name', sort: true, filter: true },
{ key: 'email', headerText: 'Email', sort: true },
]
}
Binding complex data
Angular property binding uses [property] for objects and arrays. The [data] and [columns] bindings pass values as JavaScript properties on the element, not as HTML attributes. This is the correct approach for web components that accept arrays and objects.
Accessing the grid imperatively
Use ViewChild to get a reference to the native element and call grid methods directly.
import { Component, ViewChild, ElementRef, AfterViewInit, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'
import { ApexGrid, ColumnConfiguration } from 'apex-grid'
ApexGrid.register()
interface User {
id: number
name: string
email: string
}
@Component({
selector: 'app-root',
standalone: true,
schemas: [CUSTOM_ELEMENTS_SCHEMA],
template: `
<apex-grid
#grid
[data]="users"
[columns]="columns"
></apex-grid>
`
})
export class AppComponent implements AfterViewInit {
@ViewChild('grid') gridEl!: ElementRef<ApexGrid<User>>
users: User[] = [
{ id: 1, name: 'Alice', email: 'alice@example.com' },
{ id: 2, name: 'Bob', email: 'bob@example.com' },
]
columns: ColumnConfiguration<User>[] = [
{ key: 'id', headerText: 'ID', type: 'number' },
{ key: 'name', headerText: 'Name', sort: true },
{ key: 'email', headerText: 'Email' },
]
ngAfterViewInit() {
this.gridEl.nativeElement.sort({ key: 'name', direction: 'ascending' })
}
}
Listening to events
Angular's (eventName) template binding does fire for custom DOM events dispatched by web components: Angular attaches a real DOM listener for any binding that is not a directive output, so a CustomEvent('rowSelected') reaches (rowSelected). Bind directly in the template and read the payload from $event.detail.
@Component({
standalone: true,
schemas: [CUSTOM_ELEMENTS_SCHEMA],
template: `
<apex-grid
[data]="users"
[columns]="columns"
(rowSelected)="onRowSelected($event)"
(sorted)="onSorted($event)"
></apex-grid>
`,
})
export class AppComponent {
onRowSelected(e: Event) {
console.log('selected:', (e as CustomEvent).detail)
}
onSorted(e: Event) {
console.log('sorted:', (e as CustomEvent).detail)
}
}
The binding name is case-sensitive and must match the event exactly ((rowSelected), not (rowselected)). As an alternative, for example when the event name is dynamic, attach a listener imperatively via ViewChild in ngAfterViewInit:
ngAfterViewInit() {
this.gridEl.nativeElement.addEventListener('rowSelected', (e: Event) => {
console.log('selected:', (e as CustomEvent).detail)
})
}
Commonly used events dispatched by ApexGrid (the -ing / -Changing variants fire before the operation and are cancellable; see the React guide for the complete list):
| Event | Detail |
|---|---|
rowSelected | The selected row data |
rowSelecting | The row data about to be selected |
cellValueChanged | Updated cell value and row data |
filtered | Active filter expression tree |
sorted | Active sort expression |
pageChanged | New page index |