Complete Angular v8-to-v9 migration reference: injectTable and injection context, explicit features and row-model slots, signal/atom state, FlexRender directives, type generics, prototype methods, sorting, sizing, selection, and logical pinning.
60
72%
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/migrate-v8-to-v9/SKILL.mdUse this as the complete breaking-change checklist. V9 is the current API; construction, feature registration, state, rendering, and types must migrate together.
Framework prerequisite: Angular 19 or newer (@angular/core >=19).
createAngularTable with injectTable inside an Angular injection context.tableFeatures.stockFeatures as a temporary audit bridge; explicit features are the production target.const features = tableFeatures({
rowSortingFeature,
sortedRowModel: createSortedRowModel(),
sortFns: { alphanumeric: sortFn_alphanumeric },
})
class TableCmp {
readonly table = injectTable(() => ({
features,
columns,
data: this.data(),
}))
}| v8 | v9 |
|---|---|
createAngularTable(() => options) | injectTable(() => options) in injection context |
| All features bundled | Required features: tableFeatures({...}) |
getCoreRowModel() option | Remove; core row model is automatic |
get*RowModel() table options | create*RowModel() slots in tableFeatures |
sortingFns table option | sortFns feature slot |
Top-level onStateChange | Per-slice callbacks, external atoms, or store subscription |
The initializer reruns when signals read inside it change and calls setOptions; do not rebuild columns or features there.
Feature imports are cellSelectionFeature, columnFilteringFeature, globalFilteringFeature, rowSortingFeature, rowPaginationFeature, rowSelectionFeature, rowExpandingFeature, rowPinningFeature, columnPinningFeature, columnVisibilityFeature, columnOrderingFeature, columnSizingFeature, columnResizingFeature, rowAggregationFeature, columnGroupingFeature, and columnFacetingFeature. APIs are feature-gated. Put a feature before its dependent slot in the same tableFeatures call. Aggregation is independent from grouping: register rowAggregationFeature for aggregation APIs and add columnGroupingFeature only for grouped rows.
| v8 option | v9 slot and factory |
|---|---|
getFilteredRowModel() | filteredRowModel: createFilteredRowModel() after column filtering |
getSortedRowModel() | sortedRowModel: createSortedRowModel() after row sorting |
getPaginationRowModel() | paginatedRowModel: createPaginatedRowModel() after pagination |
getExpandedRowModel() | expandedRowModel: createExpandedRowModel() after expanding |
getGroupedRowModel() | groupedRowModel: createGroupedRowModel() after grouping |
getFacetedRowModel() | facetedRowModel: createFacetedRowModel() after faceting |
getFacetedMinMaxValues() | facetedMinMaxValues: createFacetedMinMaxValues() |
getFacetedUniqueValues() | facetedUniqueValues: createFacetedUniqueValues() |
Factories take no arguments. filterFns, sortFns, and aggregationFns are sibling feature slots; register individually imported built-ins (filterFn_includesString, sortFn_alphanumeric, aggregationFn_sum) under their conventional keys. The full registry objects still work but bundle every built-in.
table.getState().sorting becomes table.atoms.sorting.get() for narrow signal-backed reads.table.store.get() only for a full flat snapshot/debug output.computed; use shallow equality for recreated object/array slices when appropriate.state and updated through matching on[State]Change callbacks; resolve value-or-function updaters.onStateChange is removed. Use per-slice callbacks, external atoms, or table.store.subscribe for all changes.@tanstack/angular-store through atoms for app-owned shared slices. Never provide both an atom and state for one slice.table.baseAtoms as internal; prefer feature APIs or external atoms.FlexRender/the current *flexRender directives from the adapter.*flexRenderCell="cell; let value", *flexRenderHeader="header; let value", and *flexRenderFooter="footer; let value"; they choose the definition and context automatically.*flexRender supports primitives, TemplateRef, component types, and flexRenderComponent(...) wrappers.inject() or use signals.injectFlexRenderContext() for the render props.flexRenderComponent(Component, { inputs, outputs, injector, bindings, directives }) for explicit component configuration; creation-time bindings/directives require the supported Angular version.tableOptions(...) composes partial options and may omit data, columns, or features until final assembly.createTableHook is optional for repeated application conventions; it returns injectAppTable and a feature-bound createAppColumnHelper.Row, cell, column, header, and related methods now live on shared prototypes and use this. Call them on their instances. Do not destructure/pass them bare or expect them in object spread, Object.keys, or JSON. Table methods are not affected.
Beta.38 has no physical aliases.
| old | new |
|---|---|
columnPinning.left / .right | .start / .end |
column.pin('left' | 'right') | column.pin('start' | 'end') |
getIsPinned() === 'left' | 'right' | 'start' | 'end' |
row.getLeftVisibleCells() / getRightVisibleCells() | getStartVisibleCells() / getEndVisibleCells() |
getLeftHeaderGroups() / getRightHeaderGroups() | getStartHeaderGroups() / getEndHeaderGroups() |
getLeftFooterGroups() / getRightFooterGroups() | getStartFooterGroups() / getEndFooterGroups() |
getLeftFlatHeaders() / getRightFlatHeaders() | getStartFlatHeaders() / getEndFlatHeaders() |
getLeftLeafHeaders() / getRightLeafHeaders() | getStartLeafHeaders() / getEndLeafHeaders() |
getLeftLeafColumns() / getRightLeafColumns() | getStartLeafColumns() / getEndLeafColumns() |
getLeftVisibleLeafColumns() / getRightVisibleLeafColumns() | getStartVisibleLeafColumns() / getEndVisibleLeafColumns() |
getLeftTotalSize() / getRightTotalSize() | getStartTotalSize() / getEndTotalSize() |
column.getStart('left') | column.getStart('start') |
column.getAfter('right') | column.getAfter('end') |
column.getIndex('left' | 'right') | column.getIndex('start' | 'end') |
Prefer CSS logical inset properties. Logical names do not set DOM direction. columnResizeDirection is unchanged.
enablePinning splits into enableColumnPinning and enableRowPinning.columnSizingFeature and columnResizingFeature; fixed sizing needs only sizing.columnSizingInfo becomes columnResizing.setColumnSizingInfo() becomes setColumnResizing().onColumnSizingInfoChange becomes onColumnResizingChange.| v8 | v9 |
|---|---|
sortingFn | sortFn |
sortingFns | sortFns |
getSortingFn() | getSortFn() |
getAutoSortingFn() | getAutoSortFn() |
SortingFn / SortingFns | SortFn / SortFns |
row._getAllCellsByColumnId() | row.getAllCellsByColumnId() |
Other _-prefixed internals are removed, including _getPinnedRows, _getFacetedRowModel, _getFacetedMinMaxValues, and _getFacetedUniqueValues.
getIsSomeRowsSelected() and getIsSomePageRowsSelected() mean at least one, including all. Use getIsSomeRowsSelected() && !getIsAllRowsSelected() or getIsSomePageRowsSelected() && !getIsAllPageRowsSelected() for indeterminate UI.
TFeatures first: Column<TFeatures, TData, TValue>, ColumnDef<TFeatures, TData, TValue>, Table<TFeatures, TData>, Row<TFeatures, TData>, and Cell<TFeatures, TData, TValue>.createColumnHelper<Person>() with createColumnHelper<typeof features, Person>(); use columnHelper.columns([...]) for inference.createTableHook column helper already binds features and needs only <Person>.StockFeatures when using stockFeatures.TableMeta/ColumnMeta declaration merging must add TFeatures first. Prefer per-table meta slots using metaHelper.FilterFns, SortFns, AggregationFns, and FilterMeta augmentation with registry slots and filterMeta; registered keys become typed string references.RowData is now Record<string, any> | Array<any> rather than unknown.Create it in a component/directive/service field initializer or another valid Angular injection context so ownership and cleanup bind correctly.
Hoist features and columns; the initializer reruns for tracked signals.
Move each row model beside its prerequisite feature in tableFeatures.
Use row.getValue('name'); prototype methods require the original instance and are absent from shallow clones.
createAngularTable is replaced by injectTable in injection context.tableFeatures; core row model is removed.onStateChange is gone.RowData use v9 shapes.stockFeatures usage has an explicit removal plan.Inspect node_modules/@tanstack/angular-table/dist/types/ for the bundled public API; do not reconstruct v9 from v8 memory.
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.