Skip to content

Commit

Permalink
feat: Angular adapter for TanStack Table (#5326) (#5432)
Browse files Browse the repository at this point in the history
* 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 <kevinvandy656@gmail.com>

* 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 <kevinvandy656@gmail.com>

* 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 <86955546+jrgokavalsa@users.noreply.github.com>
Co-authored-by: riccardoperra <riccardo.perra@icloud.com>
Co-authored-by: Riccardo Perra <perrariccardo0@gmail.com>
Co-authored-by: mamerto-g <merto.20@gmail.com>
Co-authored-by: Arnoud <6420061+arnoud-dv@users.noreply.github.com>
  • Loading branch information
6 people committed May 12, 2024
1 parent c1085a6 commit 91f4360
Show file tree
Hide file tree
Showing 191 changed files with 13,516 additions and 623 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ stats.html
*.log
.DS_Store
.cache
.idea
.pnpm-store

package-lock.json
Expand All @@ -49,3 +50,5 @@ yarn.lock
.nx/cache
vite.config.js.timestamp-*
vite.config.ts.timestamp-*

.angular
2 changes: 2 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@
**/docs
**/old-examples
pnpm-lock.yaml

.angular
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ Try other [TanStack](https://tanstack.com) libraries:

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

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

```bash
# Npm
npm install @tanstack/angular-table
npm install @tanstack/qwik-table
npm install @tanstack/react-table
npm install @tanstack/solid-table
Expand Down
2 changes: 1 addition & 1 deletion docs/api/core/table.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: Table APIs
---

## `useReactTable` / `createSolidTable` / `useQwikTable` / `useVueTable` / `createSvelteTable`
## `createAngularTable` / `useReactTable` / `createSolidTable` / `useQwikTable` / `useVueTable` / `createSvelteTable`

```tsx
type useReactTable = <TData extends AnyData>(
Expand Down
59 changes: 59 additions & 0 deletions docs/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,15 @@
}
],
"frameworks": [
{
"label": "angular",
"children": [
{
"label": "Angular Table Adapter",
"to": "framework/angular/angular-table"
}
]
},
{
"label": "qwik",
"children": [
Expand Down Expand Up @@ -128,6 +137,15 @@
}
],
"frameworks": [
{
"label": "angular",
"children": [
{
"label": "Table State",
"to": "framework/angular/guide/table-state"
}
]
},
{
"label": "qwik",
"children": [
Expand Down Expand Up @@ -364,6 +382,47 @@
"label": "Examples",
"children": [],
"frameworks": [
{
"label": "angular",
"children": [
{
"to": "framework/angular/examples/basic",
"label": "Basic"
},
{
"to": "framework/angular/examples/grouping",
"label": "Column Grouping"
},
{
"to": "framework/angular/examples/column-ordering",
"label": "Column Ordering"
},
{
"to": "framework/angular/examples/column-pinning",
"label": "Column Pinning"
},
{
"to": "column-pinning-sticky",
"label": "Sticky Column Pinning"
},
{
"to": "framework/angular/examples/column-visibility",
"label": "Column Visibility"
},
{
"to": "framework/angular/examples/filters",
"label": "Column Filters"
},
{
"to": "framework/angular/examples/row-selection",
"label": "Row Selection"
},
{
"to": "framework/angular/examples/signal-input",
"label": "Signal Input"
}
]
},
{
"label": "qwik",
"children": [
Expand Down
217 changes: 217 additions & 0 deletions docs/framework/angular/angular-table.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
---
title: Angular Table
---

The `@tanstack/angular-table` adapter is a wrapper around the core table logic. Most of it's job is related to managing
state the "angular signals" way, providing types and the rendering implementation of cell/header/footer templates.

## Exports

`@tanstack/angular-table` re-exports all of `@tanstack/table-core`'s and the following:

### `createAngularTable`

Accepts an options function or a computed value that returns the table options, and returns a table.

```ts
import {createAngularTable} from '@tanstack/angular-table'

export class AppComponent {
data = signal<Person[]>([])

table = createAngularTable(() => ({
data: this.data(),
columns: defaultColumns,
getCoreRowModel: getCoreRowModel(),
}))
}

// ...render your table in template

```

### `FlexRender`

An Angular structural directive for rendering cell/header/footer templates with dynamic values.

FlexRender supports any type of content supported by Angular:

- A string, or a html string via `innerHTML`
- A [TemplateRef](https://angular.dev/api/core/TemplateRef)
- A [Component](https://angular.dev/api/core/Component) wrapped into `FlexRenderComponent`

Example:

```ts
@Component({
imports: [FlexRenderDirective],
//...
})
```

```angular2html
<tbody>
@for (row of table.getRowModel().rows; track row.id) {
<tr>
@for (cell of row.getVisibleCells(); track cell.id) {
<td>
<ng-container
*flexRender="
cell.column.columnDef.cell;
props: cell.getContext();
let cell
"
>
<!-- if you want to render a simple string -->
{{ cell }}
<!-- if you want to render an html string -->
<div [innerHTML]="cell"></div>
</ng-container>
</td>
}
</tr>
}
</tbody>
```

#### Rendering a TemplateRef

In order to render a TemplateRef into a specific column header/cell/footer, you can pass the TemplateRef into the column
definition.

You can access the TemplateRef data via the `$implicit` property, which is valued based on what is passed in the props
field of flexRender.

In most cases, each TemplateRef will be rendered with the $implicit context valued based on the cell type in this way:

- Header: `HeaderContext<T, ?>`
- Cell: `CellContext<T, ?>`,
- Footer: `HeaderContext<T, ?>`

```angular17html
<ng-container
*flexRender="
cell.column.columnDef.cell;
props: cell.getContext();
let cell
"
>
<!-- if you want to render a simple string -->
{{ cell }}
<!-- if you want to render an html string -->
<div [innerHTML]="cell"></div>
</ng-container>
<ng-template #myCell let-context>
<!-- render something with context -->
</ng-template>
```

Full example:

```ts
import type {
CellContext,
ColumnDef,
HeaderContext,
} from '@tanstack/angular-table'
import {Component, TemplateRef, viewChild} from '@angular/core'

@Component({
template: `
<tbody>
@for (row of table.getRowModel().rows; track row.id) {
<tr>
@for (cell of row.getVisibleCells(); track cell.id) {
<td>
<ng-container
*flexRender="
cell.column.columnDef.cell;
props: cell.getContext(); // Data given to the TemplateRef
let cell
"
>
<!-- if you want to render a simple string -->
{{ cell }}
<!-- if you want to render an html string -->
<div [innerHTML]="cell"></div>
</ng-container>
</td>
}
</tr>
}
</tbody>
<ng-template #customHeader let-context>
{{ context.getValue() }}
</ng-template>
<ng-template #customCell let-context>
{{ context.getValue() }}
</ng-template>
`,
})
class AppComponent {
customHeader =
viewChild.required<TemplateRef<{ $implicit: HeaderContext<any, any> }>>(
'customHeader'
)
customCell =
viewChild.required<TemplateRef<{ $implicit: CellContext<any, any> }>>(
'customCell'
)

columns: ColumnDef<unknown>[] = [
{
id: 'customCell',
header: () => this.customHeader(),
cell: () => this.customCell(),
},
]
}
```

#### Rendering a Component

To render a Component into a specific column header/cell/footer, you can pass a `FlexRenderComponent instantiated with
your `ComponentType, with the ability to include optional parameters such as inputs and an injector.

```ts
import {FlexRenderComponent} from "@tanstack/angular-table";

class AppComponent {
columns: ColumnDef<unknown>[] = [
{
id: 'customCell',
header: () => new FlexRenderComponent(
CustomCellComponent,
{}, // optional inputs
injector // optional injector
),
cell: () => this.customCell(),
},
]
}
```

Underneath, this utilizes
the [ViewContainerRef#createComponent](https://angular.dev/api/core/ViewContainerRef#createComponent) api.
Therefore, you should declare your custom inputs using the @Input decorator or input/model signals.

You can still access the table cell context through the `injectFlexRenderContext` function, which returns the context
value based on the props you pass to the `FlexRenderDirective`.

```ts
@Component({
// ...
})
class CustomCellComponent {
// context of a cell component
readonly context = injectFlexRenderContext<CellContext<TData, TValue>>();
// context of a header/footer component
readonly context = injectFlexRenderContext<HeaderContext<TData, TValue>>();
}
```


0 comments on commit 91f4360

Please sign in to comment.