UNPKG

@tanstack/angular-table

Version:

Headless UI for building powerful tables & datagrids for Angular.

198 lines (141 loc) 6.44 kB
--- name: table-state description: > Use Angular-signal-backed table.atoms, direct template reads, computed selectors, controlled signals, value-or-updater callbacks, and external Angular Store atoms while accounting for injectTable initializer reruns. metadata: type: framework library: '@tanstack/angular-table' framework: angular library_version: '9.1.2' requires: - '@tanstack/table-core#core' - getting-started sources: - 'TanStack/table:docs/framework/angular/guide/table-state.md' - 'TanStack/table:examples/angular/basic-external-state' - 'TanStack/table:packages/angular-table/src/injectTable.ts' --- This skill builds on `@tanstack/table-core#core` and `getting-started`. Read them first for state ownership and Angular construction. ## State Mental Model TanStack Table is primarily a state coordinator. Keep state internal unless another system must read, persist, or drive it. Without `initialState`, `atoms`, `state`, or `on[State]Change`, the table owns all registered slices. - `table.baseAtoms` are internal writable atoms initialized from resolved initial state. - `table.atoms` are readonly derived atoms for the active owner of each registered slice. - `table.store` combines those atoms into one readonly flat store. The Angular adapter backs atoms with Angular signals. Reads participate in tracking inside templates, `computed`, and `effect`; signal reads inside the `injectTable` initializer also rerun that initializer and call `setOptions`. State is feature-based: missing pagination state or APIs indicate a missing `rowPaginationFeature`. Hoist stable `features` and `columns` outside the initializer, and return signal-backed `data` without mapping or slicing inline. ## Setup ```ts import { computed, signal } from '@angular/core' import { injectTable, rowPaginationFeature, tableFeatures, } from '@tanstack/angular-table' const features = tableFeatures({ rowPaginationFeature }) const columns = [{ accessorKey: 'name' }] export class TableComponent { readonly data = signal([{ name: 'Ada' }]) readonly table = injectTable(() => ({ features, columns, data: this.data() })) readonly pageIndex = computed( () => this.table.atoms.pagination.get().pageIndex, ) } ``` Angular-backed table atom reads are signal reads. Templates, `computed`, and `effect` track them directly. ## Core Patterns ### Prefer external atoms for cross-system state ```ts import { createAtom } from '@tanstack/angular-store' import type { PaginationState } from '@tanstack/angular-table' readonly paginationAtom = createAtom<PaginationState>({ pageIndex: 0, pageSize: 20 }) readonly table = injectTable(() => ({ features, columns, data: this.data(), atoms: { pagination: this.paginationAtom }, })) ``` The atom can feed Query without making every state write rerun the Table initializer. ### Resolve controlled signal updaters ```ts readonly pagination = signal({ pageIndex: 0, pageSize: 20 }) readonly table = injectTable(() => ({ features, columns, data: this.data(), state: { pagination: this.pagination() }, onPaginationChange: next => typeof next === 'function' ? this.pagination.update(next) : this.pagination.set(next), })) ``` ## Choose State Ownership Use one owner for each slice: - Prefer internal state and feature APIs for local interaction. - Use `initialState` for starting/reset values; later changes do not reset current state. - Prefer a stable atom from `@tanstack/angular-store` in `atoms` for Query or other cross-system state. Table APIs update it without a change callback. - Use an Angular signal read in `state.<slice>` plus the matching callback for simple controlled state. Handle raw values and updater functions. External atoms win over controlled `state`, which syncs into the internal base atom. Do not give a slice two owners. The global v8 `onStateChange` option is gone; subscribe to `table.store` when all state changes must be observed. ## Initialize, Update, and Reset Prefer feature methods such as `setSorting`, `nextPage`, `toggleVisibility`, and `toggleSelected`. Direct base-atom writes are a rare escape hatch for internal state; write the external atom when it owns a slice. ```ts this.table.resetSorting() this.table.resetPagination() this.table.resetPagination(true) ``` Feature resets use `table.initialState` unless `true` requests the feature default, and can update external owners. Core `table.reset()` resets internal base atoms only. Use feature-specific types such as `PaginationState`; use `TableState<typeof features>` when the complete registered state type is needed. ## Common Mistakes ### MEDIUM Wrapping atoms redundantly Wrong: ```ts readonly pagination = computed(() => computed(() => this.table.atoms.pagination.get())()) ``` Correct: ```ts readonly pagination = computed(() => this.table.atoms.pagination.get()) ``` Table atoms already bridge to Angular signals; one tracked read is sufficient. Source: `docs/framework/angular/guide/table-state.md` ### HIGH Ignoring initializer reruns Wrong: ```ts injectTable(() => ({ features: tableFeatures({ rowPaginationFeature }), columns: makeColumns(), state: { pagination: this.pagination() }, data, })) ``` Correct: ```ts injectTable(() => ({ features, columns, state: { pagination: this.pagination() }, data, })) ``` Controlled signal writes rerun the initializer, so static work must remain outside it. Source: `packages/angular-table/src/injectTable.ts` ### HIGH Storing updater functions Wrong: ```ts onPaginationChange: (next) => this.pagination.set(next) ``` Correct: ```ts onPaginationChange: (next) => typeof next === 'function' ? this.pagination.update(next) : this.pagination.set(next) ``` Callbacks receive a value or updater; assigning the function corrupts owned state. Source: `examples/angular/basic-external-state/src/app/app.ts` ### MEDIUM Giving one slice multiple owners Wrong: ```ts { initialState: { pagination: start }, atoms: { pagination: this.paginationAtom } } ``` Correct: ```ts { atoms: { pagination: this.paginationAtom } } ``` External atoms/state override initial state; choose one owner for each slice. Source: `docs/framework/angular/guide/table-state.md` ## API Discovery Inspect `node_modules/@tanstack/angular-table/dist/types/` and `reactivity.d.ts`; inspect `@tanstack/angular-store/dist/` for external atoms and installed core feature source for state APIs.