Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/framework/angular/guides/caching.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ id: caching
title: Caching Examples
---

> Please thoroughly read the [Important Defaults](../important-defaults) before reading this guide
> Please thoroughly read the [Important Defaults](./important-defaults.md) before reading this guide

## Basic Example

Expand All @@ -23,7 +23,7 @@ Let's assume we are using the default `gcTime` of **5 minutes** and the default
- A second instance of `injectQuery(() => ({ queryKey: ['todos'], queryFn: fetchTodos })` initializes elsewhere.
- Since the cache already has data for the `['todos']` key from the first query, that data is immediately returned from the cache.
- The new instance triggers a new network request using its query function.
- Note that regardless of whether both `fetchTodos` query functions are identical or not, both queries' [`status`](../../reference/injectQuery) are updated (including `isFetching`, `isPending`, and other related values) because they have the same query key.
- Note that regardless of whether both `fetchTodos` query functions are identical or not, both queries' [`status`](../../reference/injectQuery.md) are updated (including `isFetching`, `isPending`, and other related values) because they have the same query key.
- When the request completes successfully, the cache's data under the `['todos']` key is updated with the new data, and both instances are updated with the new data.
- Both instances of the `injectQuery(() => ({ queryKey: ['todos'], queryFn: fetchTodos })` query are destroyed and no longer in use.
- Since there are no more active instances of this query, a garbage collection timeout is set using `gcTime` to delete and garbage collect the query (defaults to **5 minutes**).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,4 @@ export class TodosComponent {

[//]: # 'Example2'

You can wire up your invalidations to happen using any of the callbacks available in the [`injectMutation` function](../mutations)
You can wire up your invalidations to happen using any of the callbacks available in the [`injectMutation` function](../mutations.md)
2 changes: 1 addition & 1 deletion docs/framework/angular/guides/mutation-options.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ title: Mutation Options

One of the best ways to share mutation options between multiple places,
is to use the `mutationOptions` helper. At runtime, this helper just returns whatever you pass into it,
but it has a lot of advantages when using it [with TypeScript](../../typescript#typing-query-options).
but it has a lot of advantages when using it [with TypeScript](../../typescript#typing-query-options.md).
You can define all possible options for a mutation in one place,
and you'll also get type inference and type safety for all of them.

Expand Down
2 changes: 1 addition & 1 deletion docs/framework/angular/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,4 +110,4 @@ interface Response {

## You talked me into it, so what now?

- Learn TanStack Query at your own pace with our amazingly thorough [Walkthrough Guide](../installation) and [API Reference](../reference/functions/injectquery)
- Learn TanStack Query at your own pace with our amazingly thorough [Walkthrough Guide](../installation.md) and [API Reference](../reference/functions/injectquery.md)
2 changes: 1 addition & 1 deletion examples/angular/auto-refetching/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"@angular/core": "^19.2.4",
"@angular/platform-browser": "^19.2.4",
"@angular/platform-browser-dynamic": "^19.2.4",
"@tanstack/angular-query-experimental": "^5.73.3",
"@tanstack/angular-query-experimental": "^5.74.0",
"rxjs": "^7.8.2",
"tslib": "^2.8.1",
"zone.js": "0.15.0"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"name": "Node.js",
"image": "mcr.microsoft.com/devcontainers/javascript-node:22"
}
6 changes: 6 additions & 0 deletions examples/angular/basic-persister/.eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// @ts-check

/** @type {import('eslint').Linter.Config} */
const config = {}

module.exports = config
6 changes: 6 additions & 0 deletions examples/angular/basic-persister/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# TanStack Query Angular basic persister example

To run this example:

- `npm install` or `yarn` or `pnpm i` or `bun i`
- `npm run start` or `yarn start` or `pnpm start` or `bun start`
104 changes: 104 additions & 0 deletions examples/angular/basic-persister/angular.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"cli": {
"packageManager": "pnpm",
"analytics": false,
"cache": {
"enabled": false
}
},
"newProjectRoot": "projects",
"projects": {
"basic-persister": {
"projectType": "application",
"schematics": {
"@schematics/angular:component": {
"inlineTemplate": true,
"inlineStyle": true,
"skipTests": true
},
"@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-persister",
"index": "src/index.html",
"browser": "src/main.ts",
"polyfills": ["zone.js"],
"tsConfig": "tsconfig.app.json",
"assets": ["src/favicon.ico", "src/assets"],
"styles": [],
"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-persister:build:production"
},
"development": {
"buildTarget": "basic-persister:build:development"
}
},
"defaultConfiguration": "development"
},
"extract-i18n": {
"builder": "@angular/build:extract-i18n",
"options": {
"buildTarget": "basic-persister:build"
}
}
}
}
}
}
30 changes: 30 additions & 0 deletions examples/angular/basic-persister/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"name": "@tanstack/query-example-angular-basic-persister",
"type": "module",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"watch": "ng build --watch --configuration development"
},
"private": true,
"dependencies": {
"@angular/common": "^19.2.4",
"@angular/compiler": "^19.2.4",
"@angular/core": "^19.2.4",
"@angular/platform-browser": "^19.2.4",
"@angular/platform-browser-dynamic": "^19.2.4",
"@tanstack/angular-query-experimental": "^5.74.0",
"@tanstack/angular-query-persist-client": "^5.62.7",
"@tanstack/query-sync-storage-persister": "^5.74.0",
"rxjs": "^7.8.2",
"tslib": "^2.8.1",
"zone.js": "^0.15.0"
},
"devDependencies": {
"@angular/build": "^19.2.5",
"@angular/cli": "^19.2.5",
"@angular/compiler-cli": "^19.2.4",
"typescript": "5.8.3"
}
}
10 changes: 10 additions & 0 deletions examples/angular/basic-persister/src/app/app.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<p>
Try to mock offline behavior with the button in the devtools. You can navigate
around as long as there is already data in the cache. You'll get a refetch as
soon as you go "online" again.
</p>
@if (postId() > -1) {
<post [postId]="postId()" (setPostId)="postId.set($event)"></post>
} @else {
<posts (setPostId)="postId.set($event)" />
}
13 changes: 13 additions & 0 deletions examples/angular/basic-persister/src/app/app.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { ChangeDetectionStrategy, Component, signal } from '@angular/core'
import { PostComponent } from './components/post.component'
import { PostsComponent } from './components/posts.component'

@Component({
changeDetection: ChangeDetectionStrategy.OnPush,
selector: 'basic-example',
templateUrl: './app.component.html',
imports: [PostComponent, PostsComponent],
})
export class BasicExampleComponent {
postId = signal(-1)
}
35 changes: 35 additions & 0 deletions examples/angular/basic-persister/src/app/app.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { provideHttpClient, withFetch } from '@angular/common/http'
import {
QueryClient,
provideTanStackQuery,
withDevtools,
} from '@tanstack/angular-query-experimental'
import { withPersistQueryClient } from '@tanstack/angular-query-persist-client'
import { createSyncStoragePersister } from '@tanstack/query-sync-storage-persister'
import type { ApplicationConfig } from '@angular/core'

const localStoragePersister = createSyncStoragePersister({
storage: window.localStorage,
})

export const appConfig: ApplicationConfig = {
providers: [
provideHttpClient(withFetch()),
provideTanStackQuery(
new QueryClient({
defaultOptions: {
queries: {
staleTime: 1000 * 60, // 1 minute
gcTime: 1000 * 60 * 60 * 24, // 24 hours
},
},
}),
withDevtools(),
withPersistQueryClient({
persistOptions: {
persister: localStoragePersister,
},
}),
),
],
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<div>
<div>
<a (click)="setPostId.emit(-1)" href="#"> Back </a>
</div>
@if (postQuery.isPending()) {
Loading...
} @else if (postQuery.isError()) {
Error: {{ postQuery.error().message }}
}
@if (postQuery.data(); as post) {
<h1>{{ post.title }}</h1>
<div>
<p>{{ post.body }}</p>
</div>
@if (postQuery.isFetching()) {
Background Updating...
}
}
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import {
ChangeDetectionStrategy,
Component,
EventEmitter,
Output,
inject,
input,
} from '@angular/core'
import { QueryClient, injectQuery } from '@tanstack/angular-query-experimental'
import { fromEvent, lastValueFrom, takeUntil } from 'rxjs'
import { PostsService } from '../services/posts-service'

@Component({
changeDetection: ChangeDetectionStrategy.OnPush,
selector: 'post',
standalone: true,
templateUrl: './post.component.html',
})
export class PostComponent {
#postsService = inject(PostsService)

@Output() setPostId = new EventEmitter<number>()

postId = input(0)

postQuery = injectQuery(() => ({
enabled: this.postId() > 0,
queryKey: ['post', this.postId()],
queryFn: async (context) => {
// Cancels the request when component is destroyed before the request finishes
const abort$ = fromEvent(context.signal, 'abort')
return lastValueFrom(
this.#postsService.postById$(this.postId()).pipe(takeUntil(abort$)),
)
},
}))

queryClient = inject(QueryClient)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<div>
<h1>Posts</h1>
@switch (postsQuery.status()) {
@case ('pending') {
Loading...
}
@case ('error') {
Error: {{ postsQuery.error()?.message }}
}
@default {
<div class="todo-container">
@for (post of postsQuery.data(); track post.id) {
<p>
<!-- We can access the query data here to show bold links for-->
<!-- ones that are cached-->
<a
href="#"
(click)="setPostId.emit(post.id)"
[style]="
queryClient.getQueryData(['post', post.id])
? {
fontWeight: 'bold',
color: 'green',
}
: {}
"
>{{ post.title }}</a
>
</p>
}
</div>
}
}
<div>
@if (postsQuery.isFetching()) {
Background Updating...
}
</div>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import {
ChangeDetectionStrategy,
Component,
EventEmitter,
Output,
inject,
} from '@angular/core'
import { QueryClient, injectQuery } from '@tanstack/angular-query-experimental'
import { lastValueFrom } from 'rxjs'
import { PostsService } from '../services/posts-service'

@Component({
changeDetection: ChangeDetectionStrategy.OnPush,
selector: 'posts',
standalone: true,
templateUrl: './posts.component.html',
})
export class PostsComponent {
queryClient = inject(QueryClient)
#postsService = inject(PostsService)

@Output() setPostId = new EventEmitter<number>()

postsQuery = injectQuery(() => ({
queryKey: ['posts'],
queryFn: () => lastValueFrom(this.#postsService.allPosts$()),
}))
}
Loading