@tanstack/angular-table 9.0.0-beta.4 → 9.0.0-beta.42
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/README.md +2 -0
- package/dist/fesm2022/tanstack-angular-table-experimental-worker-plugin.mjs +6 -0
- package/dist/fesm2022/tanstack-angular-table-experimental-worker-plugin.mjs.map +1 -0
- package/dist/fesm2022/tanstack-angular-table.mjs +41 -21
- package/dist/fesm2022/tanstack-angular-table.mjs.map +1 -1
- package/dist/types/tanstack-angular-table-experimental-worker-plugin.d.ts +1 -0
- package/dist/types/tanstack-angular-table.d.ts +10 -19
- package/package.json +13 -8
- package/skills/create-table-hook/SKILL.md +148 -0
- package/skills/getting-started/SKILL.md +138 -0
- package/skills/migrate-v8-to-v9/SKILL.md +194 -0
- package/skills/table-state/SKILL.md +197 -0
- package/skills/with-tanstack-query/SKILL.md +142 -0
- package/skills/with-tanstack-virtual/SKILL.md +126 -0
- package/src/flex-render/flexRenderComponent.ts +2 -2
- package/src/flex-render/view.ts +1 -1
- package/src/helpers/cell.ts +6 -2
- package/src/helpers/createTableHook.ts +44 -26
- package/src/helpers/flexRenderCell.ts +14 -0
- package/src/helpers/header.ts +4 -2
- package/src/helpers/table.ts +4 -2
- package/src/injectTable.ts +7 -12
- package/skills/angular/angular-rendering-directives/SKILL.md +0 -415
- package/skills/angular/angular-rendering-directives/references/content-shapes.md +0 -142
- package/skills/angular/angular-rendering-directives/references/create-table-hook-registries.md +0 -89
- package/skills/angular/angular-rendering-directives/references/di-tokens.md +0 -171
- package/skills/angular/angular-rendering-directives/references/flex-render-component-options.md +0 -64
- package/skills/angular/client-to-server/SKILL.md +0 -467
- package/skills/angular/compose-with-tanstack-query/SKILL.md +0 -482
- package/skills/angular/compose-with-tanstack-store/SKILL.md +0 -397
- package/skills/angular/compose-with-tanstack-virtual/SKILL.md +0 -400
- package/skills/angular/getting-started/SKILL.md +0 -496
- package/skills/angular/getting-started/references/feature-row-model-mapping.md +0 -48
- package/skills/angular/migrate-v8-to-v9/SKILL.md +0 -419
- package/skills/angular/migrate-v8-to-v9/references/v8-to-v9-mapping.md +0 -261
- package/skills/angular/production-readiness/SKILL.md +0 -469
- package/skills/angular/table-state/SKILL.md +0 -429
- package/skills/angular/table-state/references/external-atoms-and-app-hook.md +0 -152
package/skills/angular/angular-rendering-directives/references/create-table-hook-registries.md
DELETED
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
# `createTableHook` — Component Registries Reference
|
|
2
|
-
|
|
3
|
-
`createTableHook(...)` returns Angular helpers with three optional component
|
|
4
|
-
registries:
|
|
5
|
-
|
|
6
|
-
| Registry | Lives on | Inject inside it with |
|
|
7
|
-
| ------------------ | --------------------------------------------------------------------------------- | ----------------------------------------------------------- |
|
|
8
|
-
| `tableComponents` | `table.<ComponentName>` (the table object) | `injectTableContext()` |
|
|
9
|
-
| `cellComponents` | the `Cell` prototype (`cell.<ComponentName>` after `table.appCell(cell)`) | `injectTableCellContext()` (or `injectFlexRenderContext()`) |
|
|
10
|
-
| `headerComponents` | the `Header` prototype (`header.<ComponentName>` after `table.appHeader(header)`) | `injectTableHeaderContext()` |
|
|
11
|
-
|
|
12
|
-
```ts
|
|
13
|
-
import {
|
|
14
|
-
createTableHook,
|
|
15
|
-
tableFeatures,
|
|
16
|
-
rowSortingFeature,
|
|
17
|
-
} from '@tanstack/angular-table'
|
|
18
|
-
import { PaginationControls, RowCount } from './components/table-components'
|
|
19
|
-
import { TextCell, NumberCell, StatusCell } from './components/cell-components'
|
|
20
|
-
import { SortIndicator, ColumnFilter } from './components/header-components'
|
|
21
|
-
|
|
22
|
-
export const {
|
|
23
|
-
injectAppTable,
|
|
24
|
-
createAppColumnHelper,
|
|
25
|
-
injectTableContext,
|
|
26
|
-
injectTableCellContext,
|
|
27
|
-
injectTableHeaderContext,
|
|
28
|
-
} = createTableHook({
|
|
29
|
-
features: tableFeatures({ rowSortingFeature }),
|
|
30
|
-
rowModels: {
|
|
31
|
-
/* … */
|
|
32
|
-
},
|
|
33
|
-
tableComponents: { PaginationControls, RowCount },
|
|
34
|
-
cellComponents: { TextCell, NumberCell, StatusCell },
|
|
35
|
-
headerComponents: { SortIndicator, ColumnFilter },
|
|
36
|
-
})
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
Use `NgComponentOutlet` to render table components:
|
|
40
|
-
|
|
41
|
-
```html
|
|
42
|
-
<ng-container *ngComponentOutlet="table.PaginationControls" />
|
|
43
|
-
<ng-container *ngComponentOutlet="table.RowCount" />
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
Reference cell components from column defs (type-safe through
|
|
47
|
-
`createAppColumnHelper<Person>()`):
|
|
48
|
-
|
|
49
|
-
```ts
|
|
50
|
-
const columnHelper = createAppColumnHelper<Person>()
|
|
51
|
-
|
|
52
|
-
const columns = columnHelper.columns([
|
|
53
|
-
columnHelper.accessor('firstName', {
|
|
54
|
-
cell: ({ cell }) => cell.TextCell, // ✅ TS autocompletes registered components
|
|
55
|
-
}),
|
|
56
|
-
columnHelper.accessor('age', {
|
|
57
|
-
cell: ({ cell }) => cell.NumberCell,
|
|
58
|
-
}),
|
|
59
|
-
])
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
Headers via `table.appHeader(header)`:
|
|
63
|
-
|
|
64
|
-
```html
|
|
65
|
-
@for (_h of headerGroup.headers; track _h.id) { @let header =
|
|
66
|
-
table.appHeader(_h);
|
|
67
|
-
<th>
|
|
68
|
-
<ng-container *flexRenderHeader="header; let value">
|
|
69
|
-
{{ value }}
|
|
70
|
-
</ng-container>
|
|
71
|
-
<ng-container
|
|
72
|
-
*flexRender="header.SortIndicator; props: header.getContext(); let v"
|
|
73
|
-
>
|
|
74
|
-
<div [innerHTML]="v"></div>
|
|
75
|
-
</ng-container>
|
|
76
|
-
</th>
|
|
77
|
-
}
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
A header component is just an injection-context function or component:
|
|
81
|
-
|
|
82
|
-
```ts
|
|
83
|
-
export function SortIndicator(): string | null {
|
|
84
|
-
const header = injectTableHeaderContext()
|
|
85
|
-
const sorted = header().column.getIsSorted()
|
|
86
|
-
if (!sorted) return null
|
|
87
|
-
return sorted === 'asc' ? '🔼' : '🔽'
|
|
88
|
-
}
|
|
89
|
-
```
|
|
@@ -1,171 +0,0 @@
|
|
|
1
|
-
# DI Tokens & Context Injection — Full Reference
|
|
2
|
-
|
|
3
|
-
`FlexRender` automatically provides DI tokens for the render context to any
|
|
4
|
-
component rendered through `*flexRender` / `*flexRenderCell` / etc. The renderer
|
|
5
|
-
inspects the props object — if it has `table`, `header`, or `cell`, it
|
|
6
|
-
provides the matching token in the child injector.
|
|
7
|
-
|
|
8
|
-
| Helper | Returns | Available inside |
|
|
9
|
-
| ------------------------------------------- | --------------------------------- | ------------------------------------------------------------------------------------------------------ |
|
|
10
|
-
| `injectFlexRenderContext<T>()` | `T` (full props proxy) | a component rendered via `*flexRender` / `*flexRenderCell` / `*flexRenderHeader` / `*flexRenderFooter` |
|
|
11
|
-
| `injectTableContext<TData>()` | `Signal<Table<TFeatures, TData>>` | anything under `[tanStackTable]` or rendered via `*flexRender` whose context has `table` |
|
|
12
|
-
| `injectTableHeaderContext<TValue, TData>()` | `Signal<Header<...>>` | anything under `[tanStackTableHeader]` or rendered via `*flexRenderHeader` |
|
|
13
|
-
| `injectTableCellContext<TValue, TData>()` | `Signal<Cell<...>>` | anything under `[tanStackTableCell]` or rendered via `*flexRenderCell` |
|
|
14
|
-
|
|
15
|
-
The full props passed via `*flexRender`'s `props:` (or auto-derived by the
|
|
16
|
-
shorthand directives) is wrapped in a `Proxy` so property access always reads
|
|
17
|
-
the _latest_ value across re-renders.
|
|
18
|
-
|
|
19
|
-
---
|
|
20
|
-
|
|
21
|
-
## Pattern A — inject inside the rendered component itself
|
|
22
|
-
|
|
23
|
-
If your component **is** the cell, header, or footer (rendered through
|
|
24
|
-
`*flexRender*`), you don't need any extra directive — the token is auto-provided.
|
|
25
|
-
|
|
26
|
-
```ts
|
|
27
|
-
@Component({
|
|
28
|
-
template: `
|
|
29
|
-
<span>{{ context.getValue() }}</span>
|
|
30
|
-
<button (click)="context.row.toggleSelected()">Toggle</button>
|
|
31
|
-
`,
|
|
32
|
-
})
|
|
33
|
-
export class InteractiveCell {
|
|
34
|
-
readonly context = injectFlexRenderContext<CellContext<any, any, any>>()
|
|
35
|
-
}
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
Or, for just the cell signal:
|
|
39
|
-
|
|
40
|
-
```ts
|
|
41
|
-
@Component({ template: `{{ cell().getValue() }}` })
|
|
42
|
-
export class TextCell {
|
|
43
|
-
readonly cell = injectTableCellContext<string>()
|
|
44
|
-
}
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
---
|
|
48
|
-
|
|
49
|
-
## Pattern B — context for _descendants outside the FlexRender tree_
|
|
50
|
-
|
|
51
|
-
When you have a component that lives next to the `*flexRenderCell` block, or
|
|
52
|
-
when you want any nested element to inject the table/header/cell, use the
|
|
53
|
-
context **host directives**:
|
|
54
|
-
|
|
55
|
-
```ts
|
|
56
|
-
import {
|
|
57
|
-
FlexRender,
|
|
58
|
-
TanStackTable,
|
|
59
|
-
TanStackTableHeader,
|
|
60
|
-
TanStackTableCell,
|
|
61
|
-
} from '@tanstack/angular-table'
|
|
62
|
-
|
|
63
|
-
@Component({
|
|
64
|
-
imports: [FlexRender, TanStackTable, TanStackTableHeader, TanStackTableCell],
|
|
65
|
-
templateUrl: './app.html',
|
|
66
|
-
})
|
|
67
|
-
export class App {}
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
```html
|
|
71
|
-
<table [tanStackTable]="table">
|
|
72
|
-
@for (headerGroup of table.getHeaderGroups(); track headerGroup.id) {
|
|
73
|
-
<tr>
|
|
74
|
-
@for (header of headerGroup.headers; track header.id) {
|
|
75
|
-
<th [tanStackTableHeader]="header">
|
|
76
|
-
<ng-container *flexRenderHeader="header; let value">
|
|
77
|
-
{{ value }}
|
|
78
|
-
</ng-container>
|
|
79
|
-
<!-- Any component here can call injectTableHeaderContext() -->
|
|
80
|
-
</th>
|
|
81
|
-
}
|
|
82
|
-
</tr>
|
|
83
|
-
} @for (row of table.getRowModel().rows; track row.id) {
|
|
84
|
-
<tr>
|
|
85
|
-
@for (cell of row.getVisibleCells(); track cell.id) {
|
|
86
|
-
<td [tanStackTableCell]="cell">
|
|
87
|
-
<ng-container *flexRenderCell="cell; let value">{{ value }}</ng-container>
|
|
88
|
-
<app-cell-actions />
|
|
89
|
-
<!-- ↑ cell-actions calls injectTableCellContext() — no input drilling -->
|
|
90
|
-
</td>
|
|
91
|
-
}
|
|
92
|
-
</tr>
|
|
93
|
-
}
|
|
94
|
-
</table>
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
```ts
|
|
98
|
-
@Component({
|
|
99
|
-
selector: 'app-cell-actions',
|
|
100
|
-
template: `<button (click)="cell().row.toggleSelected()">Toggle</button>`,
|
|
101
|
-
})
|
|
102
|
-
export class CellActionsComponent {
|
|
103
|
-
readonly cell = injectTableCellContext()
|
|
104
|
-
}
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
Each directive uses Angular's `providers` array to register a per-host factory,
|
|
108
|
-
so contexts are correctly scoped — multiple `[tanStackTableCell]` directives on
|
|
109
|
-
sibling cells provide independent values.
|
|
110
|
-
|
|
111
|
-
---
|
|
112
|
-
|
|
113
|
-
## `*flexRender` directly (custom props)
|
|
114
|
-
|
|
115
|
-
Reach for the long form `*flexRender` when:
|
|
116
|
-
|
|
117
|
-
- You're rendering something that isn't `columnDef.cell` / `header` / `footer`
|
|
118
|
-
(e.g. a registered `headerComponents` member, see `createTableHook`).
|
|
119
|
-
- You want to override the props passed to the render function.
|
|
120
|
-
|
|
121
|
-
```html
|
|
122
|
-
<ng-container
|
|
123
|
-
*flexRender="
|
|
124
|
-
cell.column.columnDef.cell;
|
|
125
|
-
props: cell.getContext();
|
|
126
|
-
let rendered
|
|
127
|
-
"
|
|
128
|
-
>
|
|
129
|
-
{{ rendered }}
|
|
130
|
-
</ng-container>
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
Custom props (e.g. extending the default context):
|
|
134
|
-
|
|
135
|
-
```html
|
|
136
|
-
<ng-container
|
|
137
|
-
*flexRender="
|
|
138
|
-
cell.column.columnDef.cell;
|
|
139
|
-
props: {
|
|
140
|
-
...cell.getContext(),
|
|
141
|
-
extra: someValue(),
|
|
142
|
-
};
|
|
143
|
-
let rendered
|
|
144
|
-
"
|
|
145
|
-
>
|
|
146
|
-
{{ rendered }}
|
|
147
|
-
</ng-container>
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
Inside the rendered component, `injectFlexRenderContext()` returns this full
|
|
151
|
-
props object.
|
|
152
|
-
|
|
153
|
-
You can also pass `flexRenderInjector:` to override the injector used for
|
|
154
|
-
`createComponent`.
|
|
155
|
-
|
|
156
|
-
---
|
|
157
|
-
|
|
158
|
-
## Render-function injection context
|
|
159
|
-
|
|
160
|
-
Because column-def `cell` / `header` / `footer` functions run inside
|
|
161
|
-
`runInInjectionContext`, this **works** at the top of those functions:
|
|
162
|
-
|
|
163
|
-
```ts
|
|
164
|
-
cell: ({ getValue }) => {
|
|
165
|
-
const router = inject(Router) // ✅ legal
|
|
166
|
-
return router.url.endsWith('/admin') ? `[admin] ${getValue()}` : getValue()
|
|
167
|
-
}
|
|
168
|
-
```
|
|
169
|
-
|
|
170
|
-
Be deliberate: this runs every time the cell renders. For per-app values that
|
|
171
|
-
don't change, prefer `inject(...)` at the component level and close over.
|
package/skills/angular/angular-rendering-directives/references/flex-render-component-options.md
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
# `flexRenderComponent` — Full Options Reference
|
|
2
|
-
|
|
3
|
-
When you need custom inputs not derived from the render context, output
|
|
4
|
-
callbacks, a custom injector, or Angular v20+ `bindings` / `directives`,
|
|
5
|
-
**wrap the component**:
|
|
6
|
-
|
|
7
|
-
```ts
|
|
8
|
-
import { flexRenderComponent, type ColumnDef } from '@tanstack/angular-table'
|
|
9
|
-
import { EditableCell } from './editable-cell'
|
|
10
|
-
|
|
11
|
-
const columns: Array<ColumnDef<typeof features, Person>> = [
|
|
12
|
-
{
|
|
13
|
-
accessorKey: 'firstName',
|
|
14
|
-
cell: ({ getValue, row, column, table }) =>
|
|
15
|
-
flexRenderComponent(EditableCell, {
|
|
16
|
-
inputs: {
|
|
17
|
-
value: getValue(),
|
|
18
|
-
},
|
|
19
|
-
outputs: {
|
|
20
|
-
change: (value) => {
|
|
21
|
-
table.options.meta?.updateData(row.index, column.id, value)
|
|
22
|
-
},
|
|
23
|
-
},
|
|
24
|
-
}),
|
|
25
|
-
},
|
|
26
|
-
]
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
## How inputs/outputs are wired
|
|
30
|
-
|
|
31
|
-
- **`inputs`** → applied via `ComponentRef.setInput(key, value)` (works with
|
|
32
|
-
both `input()` signals and legacy `@Input()`). Diffed per change-detection
|
|
33
|
-
cycle with `KeyValueDiffers` — unchanged values are _not_ re-set, so object
|
|
34
|
-
inputs are reference-checked. Keep input objects referentially stable when
|
|
35
|
-
you can.
|
|
36
|
-
- **`outputs`** → resolved at component-instance level. The wrapper reads the
|
|
37
|
-
property by name, checks it is an `OutputEmitterRef`, and subscribes. The
|
|
38
|
-
subscription is cleaned up when the component is destroyed.
|
|
39
|
-
- **`injector`** → use when the rendered component needs to inject from a
|
|
40
|
-
specific scope (e.g. a feature module / sub-injector).
|
|
41
|
-
- **`bindings`** (Angular v20+) → forwarded directly to
|
|
42
|
-
`ViewContainerRef.createComponent` at creation time. Use this with
|
|
43
|
-
`inputBinding`, `outputBinding`, `twoWayBinding` for native programmatic
|
|
44
|
-
rendering semantics.
|
|
45
|
-
- **`directives`** (Angular v20+) → host directives forwarded the same way.
|
|
46
|
-
|
|
47
|
-
```ts
|
|
48
|
-
import { inputBinding, outputBinding, twoWayBinding, signal } from '@angular/core'
|
|
49
|
-
|
|
50
|
-
readonly name = signal('Ada')
|
|
51
|
-
|
|
52
|
-
cell: () =>
|
|
53
|
-
flexRenderComponent(EditableNameCell, {
|
|
54
|
-
bindings: [
|
|
55
|
-
inputBinding('value', this.name),
|
|
56
|
-
twoWayBinding('value', this.name),
|
|
57
|
-
outputBinding('valueChange', (v) => console.log('changed', v)),
|
|
58
|
-
],
|
|
59
|
-
})
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
> **Do not mix `bindings` with `inputs`/`outputs`** on the same component.
|
|
63
|
-
> `bindings` apply at creation time and participate in the initial CD cycle;
|
|
64
|
-
> `inputs`/`outputs` apply after. Mixing them risks double-initialization.
|