-
-
Notifications
You must be signed in to change notification settings - Fork 3.5k
feat(angular): Add angular table composability #6144
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
+3,434
−553
Merged
Changes from all commits
Commits
Show all changes
30 commits
Select commit
Hold shift + click to select a range
8b4d12e
feat(angular): wip add table context and hook helpers
riccardoperra 6e77de3
ci: apply automated fixes
autofix-ci[bot] 8a51b52
update composable table example
riccardoperra 2df745b
add some directives to provide table context
riccardoperra c085061
remove lazyInit set property workaround
riccardoperra 1b4508b
ci: apply automated fixes
autofix-ci[bot] 2dd1df3
fix garbage collection issues in angular
riccardoperra fe87811
fix: avoid creating computed cache for methods that need an object as…
riccardoperra 7bd52bc
refactor toComputed, add some tests
riccardoperra 48c70bd
refactor(injectTable): improve type definitions and enhance reactivit…
riccardoperra 80ccaf5
refactor(reactivity): enhance memoization and improve reactivity checks
riccardoperra 8c8bf84
add table cell contexts
riccardoperra 9c92b40
cleanup
riccardoperra a024ecc
fixes some examples
riccardoperra a488757
refactor flexRender to work with signals
riccardoperra 022aab1
refactor flexRender implementation to work with signals, add FlexRend…
riccardoperra 96d9286
cleanup examples
riccardoperra 87128f8
cleanup structure
riccardoperra 6fb4bac
table state selector fix for angular
riccardoperra 9591572
basic app table example
riccardoperra bc95e00
code review fixes
riccardoperra 6002827
flex render run content(props) in injection context
riccardoperra 173db1d
createTableHook add typed helpers
riccardoperra 30c57f4
refactor composable table examples with products/users table componen…
riccardoperra 9d782a8
ci: apply automated fixes
autofix-ci[bot] e6315c3
refactor table components to use inject functions and update document…
riccardoperra 6c19850
ci: apply automated fixes
autofix-ci[bot] 43014d5
fix: update comment to reflect usage of injectTable hook in app.compo…
riccardoperra 670de06
fix: update documentation for injectFlexRenderCellContext to clarify …
riccardoperra 92f0d47
fix: update RowActionsCell to use typed injectTableCellContext with P…
riccardoperra File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
4 changes: 4 additions & 0 deletions
4
examples/angular/basic-app-table/.devcontainer/devcontainer.json
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| { | ||
| "name": "Node.js", | ||
| "image": "mcr.microsoft.com/devcontainers/javascript-node:18" | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| # Editor configuration, see https://editorconfig.org | ||
| root = true | ||
|
|
||
| [*] | ||
| charset = utf-8 | ||
| indent_style = space | ||
| indent_size = 2 | ||
| insert_final_newline = true | ||
| trim_trailing_whitespace = true | ||
|
|
||
| [*.ts] | ||
| quote_type = single | ||
|
|
||
| [*.md] | ||
| max_line_length = off | ||
| trim_trailing_whitespace = false |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| # See http://help.github.com/ignore-files/ for more about ignoring files. | ||
|
|
||
| # Compiled output | ||
| /dist | ||
| /tmp | ||
| /out-tsc | ||
| /bazel-out | ||
|
|
||
| # Node | ||
| /node_modules | ||
| npm-debug.log | ||
| yarn-error.log | ||
|
|
||
| # IDEs and editors | ||
| .idea/ | ||
| .project | ||
| .classpath | ||
| .c9/ | ||
| *.launch | ||
| .settings/ | ||
| *.sublime-workspace | ||
|
|
||
| # Visual Studio Code | ||
| .vscode/* | ||
| !.vscode/settings.json | ||
| !.vscode/tasks.json | ||
| !.vscode/launch.json | ||
| !.vscode/extensions.json | ||
| .history/* | ||
|
|
||
| # Miscellaneous | ||
| /.angular/cache | ||
| .sass-cache/ | ||
| /connect.lock | ||
| /coverage | ||
| /libpeerconnection.log | ||
| testem.log | ||
| /typings | ||
|
|
||
| # System files | ||
| .DS_Store | ||
| Thumbs.db |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| # Basic | ||
|
|
||
| This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 17.1.2. | ||
|
|
||
| ## Development server | ||
|
|
||
| Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The application will automatically reload if you change any of the source files. | ||
|
|
||
| ## Code scaffolding | ||
|
|
||
| Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. | ||
|
|
||
| ## Build | ||
|
|
||
| Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. | ||
|
|
||
| ## Running unit tests | ||
|
|
||
| Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). | ||
|
|
||
| ## Running end-to-end tests | ||
|
|
||
| Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities. | ||
|
|
||
| ## Further help | ||
|
|
||
| To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,107 @@ | ||
| { | ||
| "$schema": "./node_modules/@angular/cli/lib/config/schema.json", | ||
| "version": 1, | ||
| "newProjectRoot": "projects", | ||
| "projects": { | ||
| "basic-app-table": { | ||
| "cli": { | ||
| "cache": { | ||
| "enabled": false | ||
| } | ||
| }, | ||
| "projectType": "application", | ||
| "schematics": { | ||
| "@schematics/angular:component": { | ||
| "inlineTemplate": true, | ||
| "inlineStyle": true, | ||
| "skipTests": true, | ||
| "style": "scss" | ||
| }, | ||
| "@schematics/angular:class": { | ||
| "skipTests": true | ||
| }, | ||
| "@schematics/angular:directive": { | ||
| "skipTests": true | ||
| }, | ||
| "@schematics/angular:guard": { | ||
| "skipTests": true | ||
| }, | ||
| "@schematics/angular:interceptor": { | ||
| "skipTests": true | ||
| }, | ||
| "@schematics/angular:pipe": { | ||
| "skipTests": true | ||
| }, | ||
| "@schematics/angular:resolver": { | ||
| "skipTests": true | ||
| }, | ||
| "@schematics/angular:service": { | ||
| "skipTests": true | ||
| } | ||
| }, | ||
| "root": "", | ||
| "sourceRoot": "src", | ||
| "prefix": "app", | ||
| "architect": { | ||
| "build": { | ||
| "builder": "@angular/build:application", | ||
| "options": { | ||
| "outputPath": "dist/basic-app-table", | ||
| "index": "src/index.html", | ||
| "browser": "src/main.ts", | ||
| "polyfills": ["zone.js"], | ||
| "tsConfig": "tsconfig.app.json", | ||
| "inlineStyleLanguage": "scss", | ||
| "assets": ["src/favicon.ico", "src/assets"], | ||
| "styles": ["src/styles.scss"], | ||
| "scripts": [] | ||
| }, | ||
| "configurations": { | ||
| "production": { | ||
| "budgets": [ | ||
| { | ||
| "type": "initial", | ||
| "maximumWarning": "500kb", | ||
| "maximumError": "1mb" | ||
| }, | ||
| { | ||
| "type": "anyComponentStyle", | ||
| "maximumWarning": "2kb", | ||
| "maximumError": "4kb" | ||
| } | ||
| ], | ||
| "outputHashing": "all" | ||
| }, | ||
| "development": { | ||
| "optimization": false, | ||
| "extractLicenses": false, | ||
| "sourceMap": true | ||
| } | ||
| }, | ||
| "defaultConfiguration": "production" | ||
| }, | ||
| "serve": { | ||
| "builder": "@angular/build:dev-server", | ||
| "configurations": { | ||
| "production": { | ||
| "buildTarget": "basic-app-table:build:production" | ||
| }, | ||
| "development": { | ||
| "buildTarget": "basic-app-table:build:development" | ||
| } | ||
| }, | ||
| "defaultConfiguration": "development" | ||
| }, | ||
| "extract-i18n": { | ||
| "builder": "@angular/build:extract-i18n", | ||
| "options": { | ||
| "buildTarget": "basic-app-table:build" | ||
| } | ||
| } | ||
| } | ||
| } | ||
| }, | ||
| "cli": { | ||
| "analytics": false | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| { | ||
| "name": "tanstack-table-example-angular-basic", | ||
| "version": "0.0.0", | ||
| "scripts": { | ||
| "ng": "ng", | ||
| "start": "ng serve", | ||
| "build": "ng build", | ||
| "watch": "ng build --watch --configuration development", | ||
| "test": "ng test", | ||
| "lint": "eslint ./src" | ||
| }, | ||
| "private": true, | ||
| "dependencies": { | ||
| "@angular/common": "^21.0.6", | ||
| "@angular/compiler": "^21.0.6", | ||
| "@angular/core": "^21.0.6", | ||
| "@angular/forms": "^21.0.6", | ||
| "@angular/platform-browser": "^21.0.6", | ||
| "@angular/platform-browser-dynamic": "^21.0.6", | ||
| "@angular/router": "^21.0.6", | ||
| "@tanstack/angular-table": "^9.0.0-alpha.10", | ||
riccardoperra marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| "rxjs": "~7.8.2", | ||
| "zone.js": "~0.16.0" | ||
| }, | ||
| "devDependencies": { | ||
| "@angular/build": "^21.0.4", | ||
| "@angular/cli": "^21.0.4", | ||
| "@angular/compiler-cli": "^21.0.6", | ||
| "@types/jasmine": "~5.1.13", | ||
| "jasmine-core": "~5.13.0", | ||
| "tslib": "^2.8.1", | ||
| "typescript": "5.9.3" | ||
| } | ||
| } | ||
42 changes: 42 additions & 0 deletions
42
examples/angular/basic-app-table/src/app/app.component.html
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| <div class="p-2"> | ||
| <table> | ||
| <thead> | ||
| @for (headerGroup of table.getHeaderGroups(); track headerGroup.id) { | ||
| <tr> | ||
| @for (header of headerGroup.headers; track header.id) { | ||
| @if (!header.isPlaceholder) { | ||
| <th *flexRenderHeader="header; let header"> | ||
| <div [innerHTML]="header"></div> | ||
| </th> | ||
| } | ||
| } | ||
| </tr> | ||
| } | ||
| </thead> | ||
| <tbody> | ||
| @for (row of table.getRowModel().rows; track row.id) { | ||
| <tr> | ||
| @for (cell of row.getAllCells(); track cell.id) { | ||
| <td *flexRenderCell="cell; let cell"> | ||
| <div [innerHTML]="cell"></div> | ||
| </td> | ||
| } | ||
| </tr> | ||
| } | ||
| </tbody> | ||
| <tfoot> | ||
| @for (footerGroup of table.getFooterGroups(); track footerGroup.id) { | ||
| <tr> | ||
| @for (footer of footerGroup.headers; track footer.id) { | ||
| <th *flexRenderFooter="footer; let footer"> | ||
| {{ footer }} | ||
| </th> | ||
| } | ||
| </tr> | ||
| } | ||
| </tfoot> | ||
| </table> | ||
|
|
||
| <div class="h-4"></div> | ||
| <button (click)="rerender()" class="border p-2">Rerender</button> | ||
| </div> |
119 changes: 119 additions & 0 deletions
119
examples/angular/basic-app-table/src/app/app.component.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,119 @@ | ||
| import { ChangeDetectionStrategy, Component, signal } from '@angular/core' | ||
| import { FlexRender, createTableHook } from '@tanstack/angular-table' | ||
|
|
||
| // This example uses the new `createTableHook` method to create a re-usable table hook factory instead of independently | ||
| // using the standalone `useTable` hook and `createColumnHelper` method. You can choose to use either way. | ||
|
|
||
| // 1. Define what the shape of your data will be for each row | ||
| type Person = { | ||
| firstName: string | ||
| lastName: string | ||
| age: number | ||
| visits: number | ||
| status: string | ||
| progress: number | ||
| } | ||
|
|
||
| // 2. Create some dummy data with a stable reference (this could be an API response stored in useState or similar) | ||
| const defaultData: Array<Person> = [ | ||
| { | ||
| firstName: 'tanner', | ||
| lastName: 'linsley', | ||
| age: 24, | ||
| visits: 100, | ||
| status: 'In Relationship', | ||
| progress: 50, | ||
| }, | ||
| { | ||
| firstName: 'tandy', | ||
| lastName: 'miller', | ||
| age: 40, | ||
| visits: 40, | ||
| status: 'Single', | ||
| progress: 80, | ||
| }, | ||
| { | ||
| firstName: 'joe', | ||
| lastName: 'dirte', | ||
| age: 45, | ||
| visits: 20, | ||
| status: 'Complicated', | ||
| progress: 10, | ||
| }, | ||
| { | ||
| firstName: 'kevin', | ||
| lastName: 'vandy', | ||
| age: 28, | ||
| visits: 100, | ||
| status: 'Single', | ||
| progress: 70, | ||
| }, | ||
| ] | ||
|
|
||
| // 3. New in V9! Tell the table which features and row models we want to use. | ||
| // In this case, this will be a basic table with no additional features | ||
| const { injectAppTable, createAppColumnHelper } = createTableHook({ | ||
| _features: {}, | ||
| _rowModels: {}, // client-side row models. `Core` row model is now included by default, but you can still override it here | ||
| debugTable: true, | ||
| }) | ||
|
|
||
| // 4. Create a helper object to help define our columns | ||
| const columnHelper = createAppColumnHelper<Person>() | ||
|
|
||
| // 5. Define the columns for your table with a stable reference (in this case, defined statically outside of a react component) | ||
| const columns = columnHelper.columns([ | ||
| // accessorKey method (most common for simple use-cases) | ||
| columnHelper.accessor('firstName', { | ||
| cell: (info) => info.getValue(), | ||
| footer: (info) => info.column.id, | ||
| }), | ||
| // accessorFn used (alternative) along with a custom id | ||
| columnHelper.accessor((row) => row.lastName, { | ||
| id: 'lastName', | ||
| cell: (info) => `<i>${info.getValue()}</i>`, | ||
| header: () => `<span>Last Name</span>`, | ||
| footer: (info) => info.column.id, | ||
| }), | ||
| // accessorFn used to transform the data | ||
| columnHelper.accessor((row) => Number(row.age), { | ||
| id: 'age', | ||
| header: () => 'Age', | ||
| cell: (info) => info.renderValue(), | ||
| footer: (info) => info.column.id, | ||
| }), | ||
| columnHelper.accessor('visits', { | ||
| header: () => `<span>Visits</span>`, | ||
| footer: (info) => info.column.id, | ||
| }), | ||
| columnHelper.accessor('status', { | ||
| header: 'Status', | ||
| footer: (info) => info.column.id, | ||
| }), | ||
| columnHelper.accessor('progress', { | ||
| header: 'Profile Progress', | ||
| footer: (info) => info.column.id, | ||
| }), | ||
| ]) | ||
|
|
||
| @Component({ | ||
| selector: 'app-root', | ||
| imports: [FlexRender], | ||
| templateUrl: './app.component.html', | ||
| changeDetection: ChangeDetectionStrategy.OnPush, | ||
| }) | ||
| export class AppComponent { | ||
| readonly data = signal<Array<Person>>(defaultData) | ||
|
|
||
| // 6. Create the table instance with the required columns and data. | ||
| // Features and row models are already defined in the createTableHook call above | ||
| readonly table = injectAppTable(() => ({ | ||
| columns, | ||
| data: this.data(), | ||
| // add additional table options here or in the createTableHook call above | ||
| })) | ||
|
|
||
| rerender() { | ||
| this.data.set([...defaultData.sort(() => -1)]) | ||
| } | ||
riccardoperra marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.