Skip to content

Commit 2a41a7e

Browse files
riccardoperralachlancollinsautofix-ci[bot]tannerlinsleylschierer
authored
Merge main into alpha (#5907)
* feat(angular-table): Refactor Flex render implementation - Zoneless, Better type safety, allows reactive values into cell content, re-render when cell context changes, allow to pass signal inputs into custom components (#5856) * feat: flex render granular updates * updates * cleanup * cleanup * cleanup * fix test * angular add explicit version of typescript * Fix typescript versions * add some testing for flex render in table * fix test infra * refactor flex render * update lock * fix tests, cleanup code * fix tests, cleanup code * flex render signal content support * flex render signal content support * improve view flags, handle state update in zoneless * improve view flags, handle state update in zoneless * fix * ci: apply automated fixes * clean docs test fix doc add flexRenderComponent util * test cases * fix: enable computed rowModels * fix test for rowModel * assures that `updateProps` update inputs only for Component reference type * Merge pull request #1 from riccardoperra/feat/angular-flex-render-support-output-binding add support for angular outputs in flex-render-component --------- Co-authored-by: Lachlan Collins <[email protected]> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * release: v8.21.0 * docs(angular): add editable, row-dnd and performant column resizing example (#5881) * add editable cell example * add editable cell example * row dnd exmaple * revert basic * ci: apply automated fixes * column resizing performant example * fix * fix budgets * ci: apply automated fixes * typo --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * docs(angular): add missing faker-js deps (#5883) * fix(lit-table): dynamic data updates in the Lit Table Adapter (#5884) * this fixes an issue I discussed in discord where with the lit table adapter, updating a data array did not get reflected by the table. It is a one-line change to the TableController, and a new example that demonstrates the difference. * Update packages/lit-table/src/index.ts per suggestion from @kadoshms Co-authored-by: Mor Kadosh <[email protected]> --------- Co-authored-by: Luke Schierer <[email protected]> Co-authored-by: Mor Kadosh <[email protected]> * docs: add experimental virtualization example (#5895) * docs: add experimental virtualization example * work on experimental virtualized column examples --------- Co-authored-by: Kevin Van Cott <[email protected]> * release: v8.21.1 * docs: example name * docs(angular): add expanding and sub components examples (#5898) * docs(angular): add expanding example * docs(angular): add sub components example * docs(angular): fix config.json * fix conflicts in lit package * remove angular package non-fesm export * since angular 19, ng-packgr only bundle a `fesm2022` export * docs: exp virtual - remeasure when table state changes * docs: virtualizer tbody from onchange * update all angular examples * fix conflicts in examples/react * ci: apply automated fixes * fix tests * ci: apply automated fixes * fix tests * ci: apply automated fixes * angular: update vite config to support vitest workspaces * docs(angular): fix examples * ci: apply automated fixes --------- Co-authored-by: Lachlan Collins <[email protected]> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Tanner Linsley <[email protected]> Co-authored-by: Luke Schierer <[email protected]> Co-authored-by: Luke Schierer <[email protected]> Co-authored-by: Mor Kadosh <[email protected]> Co-authored-by: Kevin Van Cott <[email protected]> Co-authored-by: Kevin Van Cott <[email protected]>
1 parent d9eba64 commit 2a41a7e

File tree

161 files changed

+9670
-3948
lines changed

Some content is hidden

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

161 files changed

+9670
-3948
lines changed

docs/config.json

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -435,9 +435,29 @@
435435
"to": "framework/angular/examples/row-selection",
436436
"label": "Row Selection"
437437
},
438+
{
439+
"to": "framework/angular/examples/expanding",
440+
"label": "Expanding"
441+
},
442+
{
443+
"to": "framework/angular/examples/sub-components",
444+
"label": "Sub Components"
445+
},
438446
{
439447
"to": "framework/angular/examples/signal-input",
440448
"label": "Signal Input"
449+
},
450+
{
451+
"to": "framework/angular/examples/editable",
452+
"label": "Editable data"
453+
},
454+
{
455+
"to": "framework/angular/examples/row-dnd",
456+
"label": "Row DnD"
457+
},
458+
{
459+
"to": "framework/angular/examples/column-resizing-performant",
460+
"label": "Performant Column Resizing"
441461
}
442462
]
443463
},
@@ -594,10 +614,18 @@
594614
"to": "framework/react/examples/virtualized-columns",
595615
"label": "Virtualized Columns"
596616
},
617+
{
618+
"to": "framework/react/examples/virtualized-columns-experimental",
619+
"label": "Virtualized Columns (Experimental)"
620+
},
597621
{
598622
"to": "framework/react/examples/virtualized-rows",
599623
"label": "Virtualized Rows"
600624
},
625+
{
626+
"to": "framework/react/examples/virtualized-rows-experimental",
627+
"label": "Virtualized Rows (Experimental)"
628+
},
601629
{
602630
"to": "framework/react/examples/virtualized-infinite-scrolling",
603631
"label": "Virtualized Infinite Scrolling"

docs/framework/angular/angular-table.md

Lines changed: 162 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -40,41 +40,181 @@ FlexRender supports any type of content supported by Angular:
4040
- A [TemplateRef](https://angular.dev/api/core/TemplateRef)
4141
- A [Component](https://angular.dev/api/core/Component) wrapped into `FlexRenderComponent`
4242

43-
Example:
43+
You can just use the `cell.renderValue` or `cell.getValue` APIs to render the cells of your table. However,
44+
these APIs will only spit out the raw cell values (from accessor functions).
45+
If you are using the `cell: () => any` column definition options, you will want to use the `FlexRenderDirective` from the adapter.
46+
47+
Cell column definition is **reactive** and runs into an **injection context**, then you can inject services or make use of signals to automatically modify the rendered content.
48+
49+
#### Example
4450

4551
```ts
4652
@Component({
4753
imports: [FlexRenderDirective],
4854
//...
4955
})
56+
class YourComponent {}
5057
```
5158

5259
```angular-html
5360
5461
<tbody>
5562
@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="
63+
<tr>
64+
@for (cell of row.getVisibleCells(); track cell.id) {
65+
<td>
66+
<ng-container
67+
*flexRender="
6168
cell.column.columnDef.cell;
6269
props: cell.getContext();
6370
let cell
6471
"
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>
72+
>
73+
<!-- if you want to render a simple string -->
74+
{{ cell }}
75+
<!-- if you want to render an html string -->
76+
<div [innerHTML]="cell"></div>
77+
</ng-container>
78+
</td>
79+
}
80+
</tr>
7481
}
7582
</tbody>
7683
```
7784

85+
#### Rendering a Component
86+
87+
To render a Component into a specific column header/cell/footer, you can pass a `FlexRenderComponent` instantiated with
88+
your `ComponentType, with the ability to include parameters such as inputs, outputs and a custom injector.
89+
90+
```ts
91+
import {flexRenderComponent} from "./flex-render-component";
92+
import {ChangeDetectionStrategy, input, output} from "@angular/core";
93+
94+
@Component({
95+
template: `
96+
...
97+
`,
98+
standalone: true,
99+
changeDetectionStrategy: ChangeDetectionStrategy.OnPush,
100+
host: {
101+
'(click)': 'clickEvent.emit($event)'
102+
}
103+
})
104+
class CustomCell {
105+
readonly content = input.required<string>();
106+
readonly cellType = input<MyType>();
107+
108+
// An output that will emit for every cell click
109+
readonly clickEvent = output<Event>();
110+
}
111+
112+
class AppComponent {
113+
columns: ColumnDef<unknown>[] = [
114+
{
115+
id: 'custom-cell',
116+
header: () => {
117+
const translateService = inject(TranslateService);
118+
return translateService.translate('...');
119+
},
120+
cell: (context) => {
121+
return flexRenderComponent(
122+
MyCustomComponent,
123+
{
124+
injector, // Optional injector
125+
inputs: {
126+
// Mandatory input since we are using `input.required()
127+
content: context.row.original.rowProperty,
128+
// cellType? - Optional input
129+
},
130+
outputs: {
131+
clickEvent: () => {
132+
// Do something
133+
}
134+
}
135+
}
136+
)
137+
},
138+
},
139+
]
140+
}
141+
```
142+
143+
Underneath, this utilizes
144+
the [ViewContainerRef#createComponent](https://angular.dev/api/core/ViewContainerRef#createComponent) api.
145+
Therefore, you should declare your custom inputs using the @Input decorator or input/model signals.
146+
147+
You can still access the table cell context through the `injectFlexRenderContext` function, which returns the context
148+
value based on the props you pass to the `FlexRenderDirective`.
149+
150+
```ts
151+
152+
@Component({
153+
// ...
154+
})
155+
class CustomCellComponent {
156+
// context of a cell component
157+
readonly context = injectFlexRenderContext<CellContext<TData, TValue>>();
158+
// context of a header/footer component
159+
readonly context = injectFlexRenderContext<HeaderContext<TData, TValue>>();
160+
}
161+
```
162+
163+
Alternatively, you can render a component into a specific column header, cell, or footer by passing the component type
164+
to the corresponding column definitions. These column definitions will be provided to the `flexRender` directive along
165+
with the `context`.
166+
167+
```ts
168+
class AppComponent {
169+
columns: ColumnDef<Person>[] = [
170+
{
171+
id: 'select',
172+
header: () => TableHeadSelectionComponent<Person>,
173+
cell: () => TableRowSelectionComponent<Person>,
174+
},
175+
]
176+
}
177+
```
178+
179+
```angular-html
180+
<ng-container
181+
*flexRender="
182+
header.column.columnDef.header;
183+
props: header.getContext();
184+
let headerCell
185+
"
186+
>
187+
{{ headerCell }}
188+
</ng-container>
189+
```
190+
191+
Properties of `context` provided in the `flexRender` directive will be accessible to your component.
192+
You can explicitly define the context properties required by your component.
193+
In this example, the context provided to flexRender is of type HeaderContext.
194+
Input signal `table`, which is a property of HeaderContext together with `column` and `header` properties,
195+
is then defined to be used in the component. If any of the context properties are
196+
needed in your component, feel free to use them. Please take note that only input signal is supported,
197+
when defining access to context properties, using this approach.
198+
199+
```angular-ts
200+
@Component({
201+
template: `
202+
<input
203+
type="checkbox"
204+
[checked]="table().getIsAllRowsSelected()"
205+
[indeterminate]="table().getIsSomeRowsSelected()"
206+
(change)="table().toggleAllRowsSelected()"
207+
/>
208+
`,
209+
// ...
210+
})
211+
export class TableHeadSelectionComponent<T> {
212+
//column = input.required<Column<T, unknown>>()
213+
//header = input.required<Header<T, unknown>>()
214+
table = input.required<Table<T>>()
215+
}
216+
```
217+
78218
#### Rendering a TemplateRef
79219

80220
In order to render a TemplateRef into a specific column header/cell/footer, you can pass the TemplateRef into the column
@@ -214,7 +354,7 @@ class CustomCellComponent {
214354
}
215355
```
216356

217-
Alternatively, you can render a component into a specific column header, cell, or footer by passing the component type
357+
Alternatively, you can render a component into a specific column header, cell, or footer by passing the component type
218358
to the corresponding column definitions. These column definitions will be provided to the `flexRender` directive along with the `context`.
219359

220360
```ts
@@ -243,12 +383,12 @@ class AppComponent {
243383
</ng-container>
244384
```
245385

246-
Properties of `context` provided in the `flexRender` directive will be accessible to your component.
247-
You can explicitly define the context properties required by your component.
248-
In this example, the context provided to flexRender is of type HeaderContext.
386+
Properties of `context` provided in the `flexRender` directive will be accessible to your component.
387+
You can explicitly define the context properties required by your component.
388+
In this example, the context provided to flexRender is of type HeaderContext.
249389
Input signal `table`, which is a property of HeaderContext together with `column` and `header` properties,
250-
is then defined to be used in the component. If any of the context properties are
251-
needed in your component, feel free to use them. Please take note that only input signal is supported,
390+
is then defined to be used in the component. If any of the context properties are
391+
needed in your component, feel free to use them. Please take note that only input signal is supported,
252392
when defining access to context properties, using this approach.
253393

254394
```angular-ts
@@ -268,4 +408,4 @@ export class TableHeadSelectionComponent<T> {
268408
//header = input.required<Header<T, unknown>>()
269409
table = input.required<Table<T>>()
270410
}
271-
```
411+
```

examples/angular/basic/package.json

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,21 @@
1111
},
1212
"private": true,
1313
"dependencies": {
14-
"@angular/common": "^19.0.5",
15-
"@angular/compiler": "^19.0.5",
16-
"@angular/core": "^19.0.5",
17-
"@angular/forms": "^19.0.5",
18-
"@angular/platform-browser": "^19.0.5",
19-
"@angular/platform-browser-dynamic": "^19.0.5",
20-
"@angular/router": "^19.0.5",
14+
"@angular/common": "^19.1.4",
15+
"@angular/compiler": "^19.1.4",
16+
"@angular/core": "^19.1.4",
17+
"@angular/forms": "^19.1.4",
18+
"@angular/platform-browser": "^19.1.4",
19+
"@angular/platform-browser-dynamic": "^19.1.4",
20+
"@angular/router": "^19.1.4",
2121
"@tanstack/angular-table": "^9.0.0-alpha.10",
2222
"rxjs": "~7.8.1",
2323
"zone.js": "~0.15.0"
2424
},
2525
"devDependencies": {
26-
"@angular/build": "^19.0.6",
27-
"@angular/cli": "^19.0.6",
28-
"@angular/compiler-cli": "^19.0.5",
26+
"@angular/build": "^19.1.5",
27+
"@angular/cli": "^19.1.5",
28+
"@angular/compiler-cli": "^19.1.4",
2929
"@types/jasmine": "~5.1.5",
3030
"jasmine-core": "~5.5.0",
3131
"tslib": "^2.8.1",

examples/angular/column-ordering/package.json

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,20 @@
1111
},
1212
"private": true,
1313
"dependencies": {
14-
"@angular/common": "^19.0.5",
15-
"@angular/compiler": "^19.0.5",
16-
"@angular/core": "^19.0.5",
17-
"@angular/forms": "^19.0.5",
18-
"@angular/platform-browser": "^19.0.5",
19-
"@angular/platform-browser-dynamic": "^19.0.5",
14+
"@angular/common": "^19.1.4",
15+
"@angular/compiler": "^19.1.4",
16+
"@angular/core": "^19.1.4",
17+
"@angular/forms": "^19.1.4",
18+
"@angular/platform-browser": "^19.1.4",
19+
"@angular/platform-browser-dynamic": "^19.1.4",
2020
"@tanstack/angular-table": "^9.0.0-alpha.10",
2121
"rxjs": "~7.8.1",
2222
"zone.js": "~0.15.0"
2323
},
2424
"devDependencies": {
25-
"@angular/build": "^19.0.6",
26-
"@angular/cli": "^19.0.6",
27-
"@angular/compiler-cli": "^19.0.5",
25+
"@angular/build": "^19.1.5",
26+
"@angular/cli": "^19.1.5",
27+
"@angular/compiler-cli": "^19.1.4",
2828
"tslib": "^2.8.1",
2929
"typescript": "5.6.3"
3030
}

examples/angular/column-pinning-sticky/package.json

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,21 @@
1111
},
1212
"private": true,
1313
"dependencies": {
14-
"@angular/common": "^19.0.5",
15-
"@angular/compiler": "^19.0.5",
16-
"@angular/core": "^19.0.5",
17-
"@angular/forms": "^19.0.5",
18-
"@angular/platform-browser": "^19.0.5",
19-
"@angular/platform-browser-dynamic": "^19.0.5",
14+
"@angular/common": "^19.1.4",
15+
"@angular/compiler": "^19.1.4",
16+
"@angular/core": "^19.1.4",
17+
"@angular/forms": "^19.1.4",
18+
"@angular/platform-browser": "^19.1.4",
19+
"@angular/platform-browser-dynamic": "^19.1.4",
2020
"@faker-js/faker": "^9.3.0",
2121
"@tanstack/angular-table": "^9.0.0-alpha.10",
2222
"rxjs": "~7.8.1",
2323
"zone.js": "~0.15.0"
2424
},
2525
"devDependencies": {
26-
"@angular/build": "^19.0.6",
27-
"@angular/cli": "^19.0.6",
28-
"@angular/compiler-cli": "^19.0.5",
26+
"@angular/build": "^19.1.5",
27+
"@angular/cli": "^19.1.5",
28+
"@angular/compiler-cli": "^19.1.4",
2929
"tslib": "^2.8.1",
3030
"typescript": "5.6.3"
3131
}

0 commit comments

Comments
 (0)