Skip to content

Commit 91f4360

Browse files
KevinVandyjrgokavalsariccardoperramerto20arnoud-dv
authored
feat: Angular adapter for TanStack Table (#5326) (#5432)
* feat(angular-table): adds Angular adapter for tanstack/table (#5326) * Angular adapter for tanstack table initial * build with: ng packagr * Add angular examples basic grouping * Add angular examples basic grouping * Update angular examples basic grouping * Add angular example selection * regen lock file * package upgrades, angular table docs * prettier * move around some deps * removed unused dependency from angular package * fix deps --------- Co-authored-by: Kevin Van Cott <[email protected]> * docs config cleanup * feat: signal angular table adapter implementation * update demo * feat: table proxy detect memoized fns * fix proxy property returning value * feat: improve naming * save new reference of table signal on every update * computed trap proxy for fns with 1 argument * update pnpm-lock.yaml * refactor proxy implementation * fix dependencies * cleanup imports * refactor basic example * fix build * run prettier * add grouping example, fix ci * add grouping example, fix ci * add row selection example * add column visibility example * update examples add signal input required example * improve angular table impl, fix flex-render change detection issues * fix build * feat(angular-table): improve adapter implementation (#5524) * feat(angular-table): support render dynamic components and templateRefs in table * update row selection example using dynamic rendered components * support change detection on push with flex render * add column ordering example * fix flexRender change detection issues * rename properties * fix prettier and adjust example budget options * update basic example * add again support for table signal * add column-pinning example * add column pinning example * add filters example * cleanup code * example cleanup * update lock file * feat(angular-table): added injector optional parameter for more flexibility (#5525) * feat(angular-table): improve adapter implementation (#5524) * Added optional injector for more flexibility * Replace runInInjectionContext with injector in effect * feat(angular-table): Added proxifyTable back * feat(angular-table): adding back notifier signal for table changed * feat(angular-table): Improve logic in setting table options *set table options inside computed before returning the table instance *remove redundant signals and effect *remove injector as it no longer required *update Grouping example to show how to pass signal when creating table * update angular adapter and state docs * prettier * update docs config with angular examples * update angular table state docs (#5545) * Angular examples and dependencies improvements (#5546) * tslib should be a dependency, see: https://angular.io/guide/angular-package-format#tslib * ensure angular examples are run as web container on code sandbox * update lock file --------- Co-authored-by: Kevin Vandy <[email protected]> * docs(angular-table): Add documentation for FlexRenderDirective (#5543) * add flexRender documentation * fix docs * fix rendering component section heading * remove double build package.json from angular build * update link name * docs pass * update esm exports in package.json * update flexrender types --------- Co-authored-by: jrgokavalsa <[email protected]> Co-authored-by: riccardoperra <[email protected]> Co-authored-by: Riccardo Perra <[email protected]> Co-authored-by: mamerto-g <[email protected]> Co-authored-by: Arnoud <[email protected]>
1 parent c1085a6 commit 91f4360

File tree

191 files changed

+13516
-623
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

191 files changed

+13516
-623
lines changed

Diff for: .gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ stats.html
3939
*.log
4040
.DS_Store
4141
.cache
42+
.idea
4243
.pnpm-store
4344

4445
package-lock.json
@@ -49,3 +50,5 @@ yarn.lock
4950
.nx/cache
5051
vite.config.js.timestamp-*
5152
vite.config.ts.timestamp-*
53+
54+
.angular

Diff for: .prettierignore

+2
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,5 @@
66
**/docs
77
**/old-examples
88
pnpm-lock.yaml
9+
10+
.angular

Diff for: README.md

+2
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ Try other [TanStack](https://tanstack.com) libraries:
4646

4747
You may know **TanStack Table** by our adapter names, too!
4848

49+
- [Angular Table](https://tanstack.com/table/v8/docs/adapters/angular-table)
4950
- [Qwik Table](https://tanstack.com/table/v8/docs/adapters/qwik-table)
5051
- [**React Table**](https://tanstack.com/table/v8/docs/adapters/react-table)
5152
- [Solid Table](https://tanstack.com/table/v8/docs/adapters/solid-table)
@@ -115,6 +116,7 @@ Install one of the following packages based on your framework of choice:
115116

116117
```bash
117118
# Npm
119+
npm install @tanstack/angular-table
118120
npm install @tanstack/qwik-table
119121
npm install @tanstack/react-table
120122
npm install @tanstack/solid-table

Diff for: docs/api/core/table.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
title: Table APIs
33
---
44

5-
## `useReactTable` / `createSolidTable` / `useQwikTable` / `useVueTable` / `createSvelteTable`
5+
## `createAngularTable` / `useReactTable` / `createSolidTable` / `useQwikTable` / `useVueTable` / `createSvelteTable`
66

77
```tsx
88
type useReactTable = <TData extends AnyData>(

Diff for: docs/config.json

+59
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,15 @@
3131
}
3232
],
3333
"frameworks": [
34+
{
35+
"label": "angular",
36+
"children": [
37+
{
38+
"label": "Angular Table Adapter",
39+
"to": "framework/angular/angular-table"
40+
}
41+
]
42+
},
3443
{
3544
"label": "qwik",
3645
"children": [
@@ -128,6 +137,15 @@
128137
}
129138
],
130139
"frameworks": [
140+
{
141+
"label": "angular",
142+
"children": [
143+
{
144+
"label": "Table State",
145+
"to": "framework/angular/guide/table-state"
146+
}
147+
]
148+
},
131149
{
132150
"label": "qwik",
133151
"children": [
@@ -364,6 +382,47 @@
364382
"label": "Examples",
365383
"children": [],
366384
"frameworks": [
385+
{
386+
"label": "angular",
387+
"children": [
388+
{
389+
"to": "framework/angular/examples/basic",
390+
"label": "Basic"
391+
},
392+
{
393+
"to": "framework/angular/examples/grouping",
394+
"label": "Column Grouping"
395+
},
396+
{
397+
"to": "framework/angular/examples/column-ordering",
398+
"label": "Column Ordering"
399+
},
400+
{
401+
"to": "framework/angular/examples/column-pinning",
402+
"label": "Column Pinning"
403+
},
404+
{
405+
"to": "column-pinning-sticky",
406+
"label": "Sticky Column Pinning"
407+
},
408+
{
409+
"to": "framework/angular/examples/column-visibility",
410+
"label": "Column Visibility"
411+
},
412+
{
413+
"to": "framework/angular/examples/filters",
414+
"label": "Column Filters"
415+
},
416+
{
417+
"to": "framework/angular/examples/row-selection",
418+
"label": "Row Selection"
419+
},
420+
{
421+
"to": "framework/angular/examples/signal-input",
422+
"label": "Signal Input"
423+
}
424+
]
425+
},
367426
{
368427
"label": "qwik",
369428
"children": [

Diff for: docs/framework/angular/angular-table.md

+217
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
---
2+
title: Angular Table
3+
---
4+
5+
The `@tanstack/angular-table` adapter is a wrapper around the core table logic. Most of it's job is related to managing
6+
state the "angular signals" way, providing types and the rendering implementation of cell/header/footer templates.
7+
8+
## Exports
9+
10+
`@tanstack/angular-table` re-exports all of `@tanstack/table-core`'s and the following:
11+
12+
### `createAngularTable`
13+
14+
Accepts an options function or a computed value that returns the table options, and returns a table.
15+
16+
```ts
17+
import {createAngularTable} from '@tanstack/angular-table'
18+
19+
export class AppComponent {
20+
data = signal<Person[]>([])
21+
22+
table = createAngularTable(() => ({
23+
data: this.data(),
24+
columns: defaultColumns,
25+
getCoreRowModel: getCoreRowModel(),
26+
}))
27+
}
28+
29+
// ...render your table in template
30+
31+
```
32+
33+
### `FlexRender`
34+
35+
An Angular structural directive for rendering cell/header/footer templates with dynamic values.
36+
37+
FlexRender supports any type of content supported by Angular:
38+
39+
- A string, or a html string via `innerHTML`
40+
- A [TemplateRef](https://angular.dev/api/core/TemplateRef)
41+
- A [Component](https://angular.dev/api/core/Component) wrapped into `FlexRenderComponent`
42+
43+
Example:
44+
45+
```ts
46+
@Component({
47+
imports: [FlexRenderDirective],
48+
//...
49+
})
50+
```
51+
52+
```angular2html
53+
54+
<tbody>
55+
@for (row of table.getRowModel().rows; track row.id) {
56+
<tr>
57+
@for (cell of row.getVisibleCells(); track cell.id) {
58+
<td>
59+
<ng-container
60+
*flexRender="
61+
cell.column.columnDef.cell;
62+
props: cell.getContext();
63+
let cell
64+
"
65+
>
66+
<!-- if you want to render a simple string -->
67+
{{ cell }}
68+
<!-- if you want to render an html string -->
69+
<div [innerHTML]="cell"></div>
70+
</ng-container>
71+
</td>
72+
}
73+
</tr>
74+
}
75+
</tbody>
76+
```
77+
78+
#### Rendering a TemplateRef
79+
80+
In order to render a TemplateRef into a specific column header/cell/footer, you can pass the TemplateRef into the column
81+
definition.
82+
83+
You can access the TemplateRef data via the `$implicit` property, which is valued based on what is passed in the props
84+
field of flexRender.
85+
86+
In most cases, each TemplateRef will be rendered with the $implicit context valued based on the cell type in this way:
87+
88+
- Header: `HeaderContext<T, ?>`
89+
- Cell: `CellContext<T, ?>`,
90+
- Footer: `HeaderContext<T, ?>`
91+
92+
```angular17html
93+
94+
<ng-container
95+
*flexRender="
96+
cell.column.columnDef.cell;
97+
props: cell.getContext();
98+
let cell
99+
"
100+
>
101+
<!-- if you want to render a simple string -->
102+
{{ cell }}
103+
<!-- if you want to render an html string -->
104+
<div [innerHTML]="cell"></div>
105+
</ng-container>
106+
107+
<ng-template #myCell let-context>
108+
<!-- render something with context -->
109+
</ng-template>
110+
```
111+
112+
Full example:
113+
114+
```ts
115+
import type {
116+
CellContext,
117+
ColumnDef,
118+
HeaderContext,
119+
} from '@tanstack/angular-table'
120+
import {Component, TemplateRef, viewChild} from '@angular/core'
121+
122+
@Component({
123+
template: `
124+
<tbody>
125+
@for (row of table.getRowModel().rows; track row.id) {
126+
<tr>
127+
@for (cell of row.getVisibleCells(); track cell.id) {
128+
<td>
129+
<ng-container
130+
*flexRender="
131+
cell.column.columnDef.cell;
132+
props: cell.getContext(); // Data given to the TemplateRef
133+
let cell
134+
"
135+
>
136+
<!-- if you want to render a simple string -->
137+
{{ cell }}
138+
<!-- if you want to render an html string -->
139+
<div [innerHTML]="cell"></div>
140+
</ng-container>
141+
</td>
142+
}
143+
</tr>
144+
}
145+
</tbody>
146+
147+
<ng-template #customHeader let-context>
148+
{{ context.getValue() }}
149+
</ng-template>
150+
<ng-template #customCell let-context>
151+
{{ context.getValue() }}
152+
</ng-template>
153+
`,
154+
})
155+
class AppComponent {
156+
customHeader =
157+
viewChild.required<TemplateRef<{ $implicit: HeaderContext<any, any> }>>(
158+
'customHeader'
159+
)
160+
customCell =
161+
viewChild.required<TemplateRef<{ $implicit: CellContext<any, any> }>>(
162+
'customCell'
163+
)
164+
165+
columns: ColumnDef<unknown>[] = [
166+
{
167+
id: 'customCell',
168+
header: () => this.customHeader(),
169+
cell: () => this.customCell(),
170+
},
171+
]
172+
}
173+
```
174+
175+
#### Rendering a Component
176+
177+
To render a Component into a specific column header/cell/footer, you can pass a `FlexRenderComponent instantiated with
178+
your `ComponentType, with the ability to include optional parameters such as inputs and an injector.
179+
180+
```ts
181+
import {FlexRenderComponent} from "@tanstack/angular-table";
182+
183+
class AppComponent {
184+
columns: ColumnDef<unknown>[] = [
185+
{
186+
id: 'customCell',
187+
header: () => new FlexRenderComponent(
188+
CustomCellComponent,
189+
{}, // optional inputs
190+
injector // optional injector
191+
),
192+
cell: () => this.customCell(),
193+
},
194+
]
195+
}
196+
```
197+
198+
Underneath, this utilizes
199+
the [ViewContainerRef#createComponent](https://angular.dev/api/core/ViewContainerRef#createComponent) api.
200+
Therefore, you should declare your custom inputs using the @Input decorator or input/model signals.
201+
202+
You can still access the table cell context through the `injectFlexRenderContext` function, which returns the context
203+
value based on the props you pass to the `FlexRenderDirective`.
204+
205+
```ts
206+
@Component({
207+
// ...
208+
})
209+
class CustomCellComponent {
210+
// context of a cell component
211+
readonly context = injectFlexRenderContext<CellContext<TData, TValue>>();
212+
// context of a header/footer component
213+
readonly context = injectFlexRenderContext<HeaderContext<TData, TValue>>();
214+
}
215+
```
216+
217+

0 commit comments

Comments
 (0)