09945509336619327a08c66b4c12001e50146120
- Restructure into standard Angular library workspace - Library source in projects/ngx-pretext-table/ - Demo app in src/ using PretextVirtualScrollDirective - Switch @chenglou/pretext dependency to npm registry (^0.0.4) - Fix moduleResolution to "bundler" for Angular 17 compatibility Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ngx-pretext-table
Variable-height virtual scrolling for PrimeNG p-table, powered by @chenglou/pretext.
PrimeNG's built-in virtual scroll only supports fixed row heights (virtualScrollItemSize). This library replaces it with pretext-calculated variable row heights — no DOM measurement, no layout thrashing, O(log n) scroll lookup.
Install
npm install ngx-pretext-table @chenglou/pretext
Usage
import { Component } from '@angular/core';
import { TableModule } from 'primeng/table';
import {
PretextVirtualScrollDirective,
PretextScrollEvent,
PretextColumnDef,
} from 'ngx-pretext-table';
@Component({
standalone: true,
imports: [TableModule, PretextVirtualScrollDirective],
template: `
<div pretextVirtualScroll
[data]="data"
[columns]="columns"
[font]="'14px system-ui'"
[lineHeight]="20"
[rowPadding]="16"
[scrollHeight]="'500px'"
(visibleRangeChange)="onRange($event)">
<p-table [value]="visibleData" [scrollable]="false">
<ng-template pTemplate="body" let-row let-i="rowIndex">
<tr [style.height.px]="rowHeights[i]">
<td>{{ row.name }}</td>
<td>{{ row.description }}</td>
</tr>
</ng-template>
</p-table>
</div>
`,
})
export class MyComponent {
data = [/* your data */];
// field + available text width (column width minus padding)
columns: PretextColumnDef[] = [
{ field: 'name', width: 184 },
{ field: 'description', width: 384 },
];
visibleData: any[] = [];
rowHeights: number[] = [];
onRange(e: PretextScrollEvent) {
this.visibleData = this.data.slice(e.start, e.end);
this.rowHeights = e.rowHeights;
}
}
API
PretextVirtualScrollDirective
| Input | Type | Default | Description |
|---|---|---|---|
data |
any[] |
required | Full data array |
columns |
PretextColumnDef[] |
required | Column field + text width |
font |
string |
'14px system-ui' |
CSS font shorthand |
lineHeight |
number |
20 |
Line height in px |
rowPadding |
number |
16 |
Vertical padding per row |
minRowHeight |
number |
32 |
Minimum row height |
rowGap |
number |
0 |
Gap between rows |
scrollHeight |
string |
'400px' |
Viewport height |
bufferRows |
number |
5 |
Buffer rows above/below |
| Output | Type | Description |
|---|---|---|
visibleRangeChange |
PretextScrollEvent |
Emits when visible range changes |
| Method | Description |
|---|---|
scrollToIndex(index, behavior?) |
Scroll to a specific row |
PretextRowHeightService
Low-level service for direct control:
const cache = service.prepareRows(data, columns, font);
const heights = service.calculateRowHeights(cache, columns, lineHeight, padding);
const positions = service.buildPositionIndex(heights);
const range = service.findVisibleRange(positions, scrollTop, viewportHeight);
How it works
- Prepare (once) —
@chenglou/pretextsegments text and measures via canvas - Layout (on resize) — pure arithmetic, ~0.0002ms per cell, no DOM access
- Scroll (continuous) — O(log n) binary search in cumulative position arrays
License
MIT
Description
Languages
TypeScript
99.3%
HTML
0.4%
SCSS
0.3%