Virtualize Angular Table final row or column models inside the correct injection and reactive lifecycle with signal counts, scroll elements, keys, measurement, transforms, sticky regions, grid/flex sizing, and infinite data.
64
78%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
Fix and improve this skill with Tessl
tessl review fix ./packages/angular-table/skills/with-tanstack-virtual/SKILL.mdThis skill builds on @tanstack/table-core#core, getting-started, and table-state. Virtual is a rendering concern over final Table models, not a feature plugin.
import { computed, viewChild } from '@angular/core'
import { injectVirtualizer } from '@tanstack/angular-virtual'
import type { ElementRef } from '@angular/core'
export class VirtualTable {
readonly scrollElement =
viewChild<ElementRef<HTMLDivElement>>('scrollElement')
readonly rows = computed(() => this.table.getRowModel().rows)
readonly rowVirtualizer = injectVirtualizer(() => ({
count: this.rows().length,
scrollElement: this.scrollElement()?.nativeElement,
estimateSize: () => 34,
getItemKey: (index) => this.rows()[index]!.id,
overscan: 5,
}))
readonly virtualRows = computed(() => this.rowVirtualizer.getVirtualItems())
readonly totalSize = computed(() => this.rowVirtualizer.getTotalSize())
}Use computed(() => table.getRowModel().rows) and computed(() => table.getVisibleLeafColumns()). injectVirtualizer tracks signal reads in its initializer and requires injection context.
Give the scroll element bounded overflow, create a total-size spacer, and translate or measure each virtual item. Use grid/flex widths for dynamic rows/columns and keep sticky headers inside the correct scroll geometry.
When the last virtual item approaches fetched length, fetch only if more server rows exist and a request is not active. Manual sorting requires server-sorted pages and a reset/refetch policy.
Wrong:
export function virtualize(options) {
return injectVirtualizer(() => options)
}Correct:
export class VirtualTable {
readonly virtualizer = injectVirtualizer(() => options())
}The Angular virtualizer follows DI lifecycle rules just like injectTable.
Source: examples/angular/virtualized-rows/src/app/app.ts
Wrong:
readonly rows = computed(() => this.data())Correct:
readonly rows = computed(() => this.table.getRowModel().rows)Raw data bypasses Table filtering, sorting, expansion, grouping, and pagination.
Source: docs/framework/angular/guide/virtualization.md
Wrong:
@for (item of virtualRows(); track item.key) {
<div>{{ rows()[item.index].id }}</div>
}Correct:
<div [style.height.px]="totalSize()" style="position:relative">
<div style="position:absolute"></div>
</div>Virtual computes ranges and sizes but does not apply DOM geometry, sticky CSS, or column widths.
Source: examples/angular/virtualized-columns/src/app/app.ts
Inspect installed @tanstack/angular-table/dist/types/, installed @tanstack/angular-virtual/dist/, and the maintained Angular examples for current row, column, measurement, and infinite patterns.
9e523bc
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.