SuperAPI AI Directory

tanstack-angular-table-with-tanstack-query

Frontend & websites

View repository

Updated 10-16 00:01

About this skill

This skill builds on @tanstack/table-core#client-vs-server, getting-started, and table-state. Decide the server-owned stages and dataset before wiring Query.

Setup

import {
  injectQuery,
  keepPreviousData,
} from '@tanstack/angular-query-experimental'
import { signal } from '@angular/core'
import {
  injectTable,
  rowPaginationFeature,
  tableFeatures,
} from '@tanstack/angular-table'

const features = tableFeatures({ rowPaginationFeature })
const EMPTY_ROWS: never[] = []

export class PeopleTable { readonly pagination = signal({ pageIndex: 0, pageSize: 20 }) readonly query = injectQuery(() => ({ queryKey: [ 'people', this.pagination().pageIndex, this.pagination().pageSize, ], queryFn: () => fetch( /api/people?page=${this.pagination().pageIndex}&size=${this.pagination().pageSize}, ).then((r) => r.json()), placeholderData: keepPreviousData, })) readonly table = injectTable(() => ({ features, columns, data: this.query.data()?.rows ?? EMPTY_ROWS, rowCount: this.query.data()?.rowCount ?? 0, manualPagination: true, state: { pagination: this.pagination() }, onPaginationChange: (next) => typeof next === 'function' ? this.pagination.update(next) : this.pagination.set(next), })) }


## Core Patterns

### Track every server-owned input

Read pagination, sorting, and filtering signals inside `injectQuery(() => ...)` and include them in the query key. Return data already processed for each manual stage.

### Keep Query data authoritative

Read the Query signal directly in `injectTable`. Create another signal only for a deliberate editable draft with an explicit cache synchronization policy.

## Common Mistakes

### HIGH Capturing query inputs outside tracking

Wrong:

```ts
const page = this.pagination().pageIndex
readonly query = injectQuery(() => ({ queryKey: ['people', page], queryFn }))

Correct:

readonly query = injectQuery(() => ({ queryKey: ['people', this.pagination().pageIndex], queryFn }))

Signal reads inside the options function establish refetch dependencies.

Source: examples/angular/with-tanstack-query/src/app/app.ts

HIGH Expecting manual mode to request

Wrong:

injectTable(() => ({ features, columns, data, manualPagination: true }))

Correct:

injectTable(() => ({
  features,
  columns,
  data: this.query.data()?.rows ?? EMPTY_ROWS,
  manualPagination: true,
}))

Manual flags only bypass client row processing; Query performs network work.

Source: examples/angular/with-tanstack-query/src/app/app.ts

HIGH Omitting total counts

Wrong:

{ data: this.query.data()?.rows ?? EMPTY_ROWS, manualPagination: true }

Correct:

{ data: this.query.data()?.rows ?? EMPTY_ROWS, rowCount: this.query.data()?.rowCount ?? 0, manualPagination: true }

Table needs rowCount or pageCount to constrain navigation across server pages.

Source: docs/framework/angular/guide/pagination.md

API Discovery

Inspect installed @tanstack/angular-table/dist/types/, the relevant core feature source, and installed Angular Query source for the exact injectQuery package/version contract.