Frontend & UISûr100100/100
Angular DB (TanStack)
Angular bindings for TanStack DB. injectLiveQuery inject function with Angular signals (Signal<T>) for all return values. Reactive params pattern ({ params: () => T, query: ({ params, q }) => QueryBuilder }) for dynamic queries. Must be called in injection context. Angular 17+ control flow (@if, @for) and signal inputs supported. Import from @tanstack/angular-db (re-exports all of @tanstack/db).
ou envoie-le directement à ton agent.
Installer dans ton projet
$ curl -fsSL https://arboristhree.xyz/cli/install-skill.mjs -o /tmp/arboris-install-skill.mjs && node /tmp/arboris-install-skill.mjs angular-db__tanstack-db__packages-angular-db-skills-01d96206dd64TanStack
TanStack/db
Contenu à copier
---
name: angular-db
description: >
Angular bindings for TanStack DB. injectLiveQuery inject function with
Angular signals (Signal<T>) for all return values. Reactive params pattern
({ params: () => T, query: ({ params, q }) => QueryBuilder }) for dynamic
queries. Must be called in injection context. Angular 17+ control flow
(@if, @for) and signal inputs supported. Import from
@tanstack/angular-db (re-exports all of @tanstack/db).
type: framework
library: db
framework: angular
library_version: '0.6.17'
requires:
- db-core
sources:
- 'TanStack/db:docs/framework/angular/overview.md'
- 'TanStack/db:packages/angular-db/src/index.ts'
metadata:
origin: TanStack
---
This skill builds on db-core. Read it first for collection setup, query builder, and mutation patterns.
# TanStack DB — Angular
## Setup
```typescript
import { Component } from '@angular/core'
import { injectLiveQuery, eq, not } from '@tanstack/angular-db'
@Component({
selector: 'app-todo-list',
standalone: true,
template: `
@if (query.isLoading()) {
<div>Loading...</div>
} @else {
<ul>
@for (todo of query.data(); track todo.id) {
<li>{{ todo.text }}</li>
}
</ul>
}
`,
})
export class TodoListComponent {
query = injectLiveQuery((q) =>
q
.from({ todos: todosCollection })
.where(({ todos }) => not(todos.completed))
.orderBy(({ todos }) => todos.created_at, 'asc'),
)
}
```
`@tanstack/angular-db` re-exports everything from `@tanstack/db`.
## Inject Function
### injectLiveQuery
Returns an object with Angular `Signal<T>` properties — call with `()` in templates:
```typescript
// Static query — no reactive dependencies
const query = injectLiveQuery((q) => q.from({ todo: todoCollection }))
// query.data() → Array<T>
// query.status() → CollectionStatus | 'disabled'
// query.isLoading(), query.isReady(), query.isError()
// query.isIdle(), query.isCleanedUp() (seldom used)
// query.state() → Map<TKey, T>
// query.collection() → Collection | null
// Reactive params — re-runs when params change
const query = injectLiveQuery({
params: () => ({ minPriority: this.minPriority() }),
query: ({ params, q }) =>
q
.from({ todo: todoCollection })
.where(({ todo }) => gt(todo.priority, params.minPriority)),
})
// Config object
const query = injectLiveQuery({
query: (q) => q.from({ todo: todoCollection }),
gcTime: 60000,
})
// Pre-created collection
const query = injectLiveQuery(preloadedCollection)
// Conditional query — return undefined/null to disable
const query = injectLiveQuery({
params: () => ({ userId: this.userId() }),
query: ({ params, q }) => {
if (!params.userId) return undefined
return q
.from({ todo: todoCollection })
.where(({ todo }) => eq(todo.userId, params.userId))
},
})
```
A bare `{ query }` config defaults to `startSync: true` and `gcTime: 1`, like
the query-function overload. Explicit values in the config override those
defaults.
## Angular-Specific Patterns
### Reactive params with signals
```typescript
@Component({
selector: 'app-filtered-todos',
standalone: true,
template: `<div>{{ query.data().length }} todos</div>`,
})
export class FilteredTodosComponent {
minPriority = signal(5)
query = injectLiveQuery({
params: () => ({ minPriority: this.minPriority() }),
query: ({ params, q }) =>
q
.from({ todos: todosCollection })
.where(({ todos }) => gt(todos.priority, params.minPriority)),
})
}
```
When `params()` return value changes, the previous collection is disposed and a new query is created.
### Signal inputs (Angular 17+)
```typescript
@Component({
selector: 'app-user-todos',
standalone: true,
template: `<div>{{ query.data().length }} todos</div>`,
})
export class UserTodosComponent {
userId = input.required<number>()
query = injectLiveQuery({
params: () => ({ userId: this.userId() }),
query: ({ params, q }) =>
q
.from({ todo: todoCollection })
.where(({ todo }) => eq(todo.userId, params.userId)),
})
}
```
### Legacy @Input (Angular 16)
```typescript
export class UserTodosComponent {
@Input({ required: true }) userId!: number
query = injectLiveQuery({
params: () => ({ userId: this.userId }),
query: ({ params, q }) =>
q
.from({ todo: todoCollection })
.where(({ todo }) => eq(todo.userId, params.userId)),
})
}
```
### Template syntax
Angular 17+ control flow:
```html
@if (query.isLoading()) {
<div>Loading...</div>
} @else { @for (todo of query.data(); track todo.id) {
<li>{{ todo.text }}</li>
} }
```
Angular 16 structural directives:
```html
<div *ngIf="query.isLoading()">Loading...</div>
<li *ngFor="let todo of query.data(); trackBy: trackById">{{ todo.text }}</li>
```
## Includes (Hierarchical Data)
When a query uses includes (subqueries in `select`), each child field is a live `Collection` by default. Subscribe to it with `injectLiveQuery` in a child component:
```typescript
@Component({
selector: 'app-project-list',
standalone: true,
imports: [IssueListComponent],
template: `
@for (project of query.data(); track project.id) {
<div>
{{ project.name }}
<app-issue-list [issuesCollection]="project.issues" />
</div>
}
`,
})
export class ProjectListComponent {
query = injectLiveQuery((q) =>
q.from({ p: projectsCollection }).select(({ p }) => ({
id: p.id,
name: p.name,
issues: q
.from({ i: issuesCollection })
.where(({ i }) => eq(i.projectId, p.id))
.select(({ i }) => ({ id: i.id, title: i.title })),
})),
)
}
// Child component subscribes to the child Collection
@Component({
selector: 'app-issue-list',
standalone: true,
template: `
@for (issue of query.data(); track issue.id) {
<li>{{ issue.title }}</li>
}
`,
})
export class IssueListComponent {
issuesCollection = input.required<Collection>()
query = injectLiveQuery(this.issuesCollection())
}
```
With `toArray()`, child results are plain arrays and the parent re-emits on child changes:
```typescript
import { toArray, eq } from '@tanstack/angular-db'
query = injectLiveQuery((q) =>
q.from({ p: projectsCollection }).select(({ p }) => ({
id: p.id,
name: p.name,
issues: toArray(
q
.from({ i: issuesCollection })
.where(({ i }) => eq(i.projectId, p.id))
.select(({ i }) => ({ id: i.id, title: i.title })),
),
})),
)
// project.issues is a plain array — no child component subscription needed
```
See db-core/live-queries/SKILL.md for full includes rules (correlation conditions, nested includes, aggregates).
## Common Mistakes
### CRITICAL Using injectLiveQuery outside injection context
Wrong:
```typescript
export class TodoComponent {
ngOnInit() {
this.query = injectLiveQuery((q) => q.from({ todo: todoCollection }))
}
}
```
Correct:
```typescript
export class TodoComponent {
query = injectLiveQuery((q) => q.from({ todo: todoCollection }))
}
```
`injectLiveQuery` calls `assertInInjectionContext` internally — it must be called during construction (field initializer or constructor), not in lifecycle hooks.
Source: packages/angular-db/src/index.ts
### HIGH Using query function for reactive values instead of params
Wrong:
```typescript
export class FilteredComponent {
status = signal('active')
query = injectLiveQuery((q) =>
q
.from({ todo: todoCollection })
.where(({ todo }) => eq(todo.status, this.status())),
)
}
```
Correct:
```typescript
export class FilteredComponent {
status = signal('active')
query = injectLiveQuery({
params: () => ({ status: this.status() }),
query: ({ params, q }) =>
q
.from({ todo: todoCollection })
.where(({ todo }) => eq(todo.status, params.status)),
})
}
```
The plain query function overload does not track Angular signal reads. Use the `params` pattern to make reactive values trigger query re-creation.
Source: packages/angular-db/src/index.ts
### MEDIUM Forgetting to call signals in templates
Wrong:
```html
<div>{{ query.data.length }}</div>
```
Correct:
```html
<div>{{ query.data().length }}</div>
```
All return values are Angular signals. Without `()`, you get the signal object, not the value.
See also: db-core/live-queries/SKILL.md — for query builder API.
See also: db-core/mutations-optimistic/SKILL.md — for mutation patterns.Colle ce Markdown dans ton agent ou utilise les boutons ci-dessus pour l’écrire dans ton projet.
Ce que fait Angular DB (TanStack)
Applique les pratiques du skill angular-db__tanstack-db__packages-angular-db-skills-01d96206dd64.
Comment utiliser Angular DB (TanStack)
1
Copie le prompt
Un clic copie le prompt packagé (ou l'envoie à ton agent).
2
L'agent installe le skill
Il ajoute le SKILL.md et ses ressources à ton projet.
3
Activation automatique
Le skill s'active dès que le contexte correspond.
Déclencheurs pour Angular DB (TanStack)
Dis simplement à ton agent quelque chose comme :
Applique le skill angular-db__tanstack-db__packages-angular-db-skills-01d96206dd64 à cette tâche
Utilise angular-db__tanstack-db__packages-angular-db-skills-01d96206dd64 pour améliorer cette implémentation
Passe en revue ce sujet avec angular-db__tanstack-db__packages-angular-db-skills-01d96206dd64
Skills liés à Angular DB (TanStack)
accessibility
Design, implement, and audit accessible UI to WCAG 2.2 Level AA across Web, iOS, and Android — semantic ARIA roles and labels, accessibility traits and hints, focus management, contrast, target size, and screen-reader support. Use when building or auditing UI for accessibility compliance, keyboard navigation, or screen-reader support.Accessibility Pass (Microsoft)
Use this skill whenever the user asks to check, review, or fix the accessibility of a PowerPoint deck, Word document, HTML page, or Markdown file, and before handing over any deck or document this agent just generated, so it does not ship with missing alt text, untitled slides, or unreadable colour contrast.Add Connector (Microsoft)
Use when adding a Power Platform connector to an Expo/React Native Power Apps mobile app and no dedicated mobile connector skill exists.