CtrlK
BlogDocsLog inGet started
Tessl Logo

with-tanstack-query

Compose Angular Query with signal-owned Table filtering, sorting, and pagination state using reactive query options, manual row-model boundaries, direct query data, server counts, and valid injection context.

61

Quality

73%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide

SecuritybySnyk

Passed

No findings from the security scan

Fix and improve this skill with Tessl

tessl review fix ./packages/angular-table/skills/with-tanstack-query/SKILL.md
SKILL.md
Quality
Evals
Security

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:

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.

Repository
TanStack/table
Last updated
First committed

Is this your skill?

If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.