Skip to content

Commit

Permalink
docs(angular-query): add query options from a service example (#8220)
Browse files Browse the repository at this point in the history
  • Loading branch information
arnoud-dv authored Oct 25, 2024
1 parent 1865f0d commit c61ff1e
Show file tree
Hide file tree
Showing 25 changed files with 477 additions and 16 deletions.
4 changes: 4 additions & 0 deletions docs/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -1053,6 +1053,10 @@
{
"label": "RxJS autocomplete",
"to": "framework/angular/examples/rxjs"
},
{
"label": "Query options from a service",
"to": "framework/angular/examples/query-options-from-a-service"
}
]
}
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:18"
}
6 changes: 6 additions & 0 deletions examples/angular/query-options-from-a-service/.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/query-options-from-a-service/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# TanStack Query Angular query options from a service 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/query-options-from-a-service/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": {
"query-options-from-a-service": {
"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-devkit/build-angular:application",
"options": {
"outputPath": "dist/query-options-from-a-service",
"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-devkit/build-angular:dev-server",
"configurations": {
"production": {
"buildTarget": "query-options-from-a-service:build:production"
},
"development": {
"buildTarget": "query-options-from-a-service:build:development"
}
},
"defaultConfiguration": "development"
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"buildTarget": "query-options-from-a-service:build"
}
}
}
}
}
}
30 changes: 30 additions & 0 deletions examples/angular/query-options-from-a-service/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"name": "@tanstack/query-example-angular-query-options-from-a-service",
"type": "module",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"watch": "ng build --watch --configuration development"
},
"private": true,
"dependencies": {
"@angular/common": "^17.3.12",
"@angular/compiler": "^17.3.12",
"@angular/core": "^17.3.12",
"@angular/platform-browser": "^17.3.12",
"@angular/platform-browser-dynamic": "^17.3.12",
"@angular/router": "^17.3.12",
"@tanstack/angular-query-experimental": "^5.59.16",
"rxjs": "^7.8.1",
"tslib": "^2.6.3",
"zone.js": "^0.14.8"
},
"devDependencies": {
"@angular-devkit/build-angular": "^17.3.8",
"@angular/cli": "^17.3.8",
"@angular/compiler-cli": "^17.3.12",
"@tanstack/angular-query-devtools-experimental": "^5.59.16",
"typescript": "5.3.3"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<p>
As you visit the posts below, you will notice them in a loading state the
first time you load them. However, after you return to this list and click on
any posts you have already visited again, you will see them load instantly and
background refresh right before your eyes!
<strong>
(You may need to throttle your network speed to simulate longer loading
sequences)
</strong>
</p>
<angular-query-devtools initialIsOpen />
<router-outlet />
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Component } from '@angular/core'
import { RouterOutlet } from '@angular/router'
import { AngularQueryDevtools } from '@tanstack/angular-query-devtools-experimental'

@Component({
selector: 'app-root',
standalone: true,
imports: [AngularQueryDevtools, RouterOutlet],
templateUrl: './app.component.html',
styles: [],
})
export class AppComponent {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { provideHttpClient, withFetch } from '@angular/common/http'
import { provideRouter, withComponentInputBinding } from '@angular/router'
import {
QueryClient,
provideAngularQuery,
} from '@tanstack/angular-query-experimental'

import { routes } from './app.routes'
import type { ApplicationConfig } from '@angular/core'

export const appConfig: ApplicationConfig = {
providers: [
provideAngularQuery(new QueryClient()),
provideHttpClient(withFetch()),
provideRouter(routes, withComponentInputBinding()),
],
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import type { Route } from '@angular/router'

// loadComponent lazily loads the component
// when the component is the default export, there is no need to handle the promise

export const routes: Array<Route> = [
{
path: '',
loadComponent: () => import('./components/posts.component'),
},
{
path: 'post/:postId',
loadComponent: () => import('./components/post.component'),
},
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<div>
<div>
<a routerLink="/" 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,27 @@
import {
ChangeDetectionStrategy,
Component,
inject,
input,
numberAttribute,
} from '@angular/core'
import { RouterLink } from '@angular/router'
import { injectQuery } from '@tanstack/angular-query-experimental'
import { QueriesService } from '../services/queries-service'

@Component({
changeDetection: ChangeDetectionStrategy.OnPush,
selector: 'post',
standalone: true,
templateUrl: './post.component.html',
imports: [RouterLink],
})
export default class PostComponent {
private queries = inject(QueriesService)

postId = input.required({
transform: numberAttribute,
})

postQuery = injectQuery(() => this.queries.post(this.postId()))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<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
routerLink="post/{{ 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,21 @@
import { ChangeDetectionStrategy, Component, inject } from '@angular/core'
import { RouterLink } from '@angular/router'
import {
injectQuery,
injectQueryClient,
} from '@tanstack/angular-query-experimental'
import { QueriesService } from '../services/queries-service'

@Component({
changeDetection: ChangeDetectionStrategy.OnPush,
selector: 'posts',
standalone: true,
templateUrl: './posts.component.html',
imports: [RouterLink],
})
export default class PostsComponent {
private queries = inject(QueriesService)

postsQuery = injectQuery(() => this.queries.posts())
queryClient = injectQueryClient()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { HttpClient } from '@angular/common/http'
import { Injectable, inject } from '@angular/core'

@Injectable({
providedIn: 'root',
})
export class PostsService {
#http = inject(HttpClient)

postById$ = (postId: number) =>
this.#http.get<Post>(`https://jsonplaceholder.typicode.com/posts/${postId}`)

allPosts$ = () =>
this.#http.get<Array<Post>>('https://jsonplaceholder.typicode.com/posts')
}

export interface Post {
id: number
title: string
body: string
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { Injectable, inject } from '@angular/core'
import { lastValueFrom } from 'rxjs'
import { queryOptions } from '@tanstack/angular-query-experimental'
import { PostsService } from './posts-service'

@Injectable({
providedIn: 'root',
})
export class QueriesService {
private postsService = inject(PostsService)

post(postId: number) {
return queryOptions({
queryKey: ['post', postId],
queryFn: () => {
return lastValueFrom(this.postsService.postById$(postId))
},
})
}

posts() {
return queryOptions({
queryKey: ['posts'],
queryFn: () => lastValueFrom(this.postsService.allPosts$()),
})
}
}
Empty file.
Binary file not shown.
13 changes: 13 additions & 0 deletions examples/angular/query-options-from-a-service/src/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>TanStack Query Angular query options from a service example</title>
<base href="/" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" type="image/x-icon" href="favicon.ico" />
</head>
<body>
<app-root></app-root>
</body>
</html>
Loading

0 comments on commit c61ff1e

Please sign in to comment.