snapshot of https://github.com/TanStack/query.git (main, 2026-09-16; blobs > 131072B omitted)
This commit is contained in:
184
docs/framework/angular/reference/functions/injectMutation.md
Normal file
184
docs/framework/angular/reference/functions/injectMutation.md
Normal file
@@ -0,0 +1,184 @@
|
||||
---
|
||||
id: injectMutation
|
||||
title: injectMutation
|
||||
---
|
||||
|
||||
```ts
|
||||
function injectMutation<TData, TError, TVariables, TOnMutateResult>(injectMutationFn, options?): CreateMutationResult<TData, TError, TVariables, TOnMutateResult>;
|
||||
```
|
||||
|
||||
Defined in: [packages/angular-query-experimental/src/inject-mutation.ts:174](https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/inject-mutation.ts#L174)
|
||||
|
||||
Unlike queries, mutations are typically used to create/update/delete data or perform server side-effects.
|
||||
`injectMutation` is the function for that. Unlike queries, mutations are not run automatically.
|
||||
|
||||
## Type Parameters
|
||||
|
||||
### TData
|
||||
|
||||
`TData` = `unknown`
|
||||
|
||||
### TError
|
||||
|
||||
`TError` = `Error`
|
||||
|
||||
### TVariables
|
||||
|
||||
`TVariables` = `void`
|
||||
|
||||
### TOnMutateResult
|
||||
|
||||
`TOnMutateResult` = `unknown`
|
||||
|
||||
## Parameters
|
||||
|
||||
### injectMutationFn
|
||||
|
||||
() => [`CreateMutationOptions`](../interfaces/CreateMutationOptions.md)\<`TData`, `TError`, `TVariables`, `TOnMutateResult`\>
|
||||
|
||||
A function that returns mutation options. Similar to `computed` from Angular,
|
||||
this function runs in the reactive context, so signals read inside it drive the mutation's options.
|
||||
|
||||
### options?
|
||||
|
||||
[`InjectMutationOptions`](../interfaces/InjectMutationOptions.md)
|
||||
|
||||
Additional configuration
|
||||
|
||||
## Returns
|
||||
|
||||
[`CreateMutationResult`](../type-aliases/CreateMutationResult.md)\<`TData`, `TError`, `TVariables`, `TOnMutateResult`\>
|
||||
|
||||
The mutation result. Value fields are exposed as a `Signal` — read `data`/`error` by calling them
|
||||
(e.g. `mutation.data()`) — while function fields (`mutate`, `mutateAsync`, `reset`) are called directly,
|
||||
unchanged. `isSuccess`/`isError`/`isPending`/`isIdle` are type-guard methods you can call to narrow whether
|
||||
`data` is defined.
|
||||
|
||||
## Remarks
|
||||
|
||||
`mutate`/`mutateAsync` also accept per-call `onSuccess`/`onError`/`onSettled` callbacks as a
|
||||
second argument, useful for triggering call-site side effects (e.g. navigation) without coupling them to
|
||||
the shared mutation definition. Callbacks defined in `injectMutationFn` fire for every mutation; per-call
|
||||
callbacks fire only for the latest call you've made — `mutateAsync` gives you a promise per call instead,
|
||||
so you can await `Promise.all`/`Promise.allSettled` over several calls and see each one's outcome.
|
||||
|
||||
## See
|
||||
|
||||
[mutationOptions](mutationOptions.md) to share these options across multiple `injectMutation` call sites, or to look
|
||||
the mutation up elsewhere via its `mutationKey` (e.g. with `injectMutationState`).
|
||||
|
||||
## Examples
|
||||
|
||||
```angular-ts
|
||||
@Component({
|
||||
selector: 'todos',
|
||||
template: `
|
||||
@if (addMutation.isPending()) {
|
||||
<span>Adding todo...</span>
|
||||
} @else if (addMutation.isError()) {
|
||||
<div>An error occurred: {{ addMutation.error()?.message }}</div>
|
||||
}
|
||||
<button (click)="addMutation.mutate('Item')">Add</button>
|
||||
`,
|
||||
})
|
||||
export class Todos {
|
||||
readonly #queryClient = inject(QueryClient)
|
||||
|
||||
readonly addMutation = injectMutation(() => ({
|
||||
mutationFn: addTodo,
|
||||
onSuccess: () => this.#queryClient.invalidateQueries({ queryKey: ['todos'] }),
|
||||
}))
|
||||
}
|
||||
```
|
||||
|
||||
Optimistic update via `onMutate`, rolling back on `onError`:
|
||||
```angular-ts
|
||||
@Component({
|
||||
selector: 'todos',
|
||||
template: `<button (click)="addMutation.mutate('Item')">Add</button>`,
|
||||
})
|
||||
export class Todos {
|
||||
readonly #queryClient = inject(QueryClient)
|
||||
|
||||
readonly addMutation = injectMutation(() => ({
|
||||
mutationFn: addTodo,
|
||||
onMutate: async (newTodo) => {
|
||||
await this.#queryClient.cancelQueries({ queryKey: ['todos'] })
|
||||
const previousTodos = this.#queryClient.getQueryData<Array<string>>(['todos'])
|
||||
|
||||
this.#queryClient.setQueryData<Array<string>>(['todos'], (old) => [
|
||||
...(old ?? []),
|
||||
newTodo,
|
||||
])
|
||||
|
||||
// Passed to `onError` as `onMutateResult` if the mutation fails.
|
||||
return { previousTodos }
|
||||
},
|
||||
onError: (_err, _newTodo, onMutateResult) => {
|
||||
this.#queryClient.setQueryData(['todos'], onMutateResult?.previousTodos)
|
||||
},
|
||||
onSettled: () => {
|
||||
this.#queryClient.invalidateQueries({ queryKey: ['todos'] })
|
||||
},
|
||||
}))
|
||||
}
|
||||
```
|
||||
|
||||
Callbacks passed per call to `mutate` only fire for the last call — `mutateAsync` gives you a promise per
|
||||
call instead, so you can wait for all of them when they succeed:
|
||||
```angular-ts
|
||||
@Component({
|
||||
selector: 'todos',
|
||||
template: `
|
||||
<button (click)="handleAddAll(['Todo 1', 'Todo 2', 'Todo 3'])">Add all</button>
|
||||
`,
|
||||
})
|
||||
export class Todos {
|
||||
readonly #queryClient = inject(QueryClient)
|
||||
|
||||
readonly addMutation = injectMutation(() => ({
|
||||
mutationFn: addTodo,
|
||||
onSuccess: () => this.#queryClient.invalidateQueries({ queryKey: ['todos'] }),
|
||||
}))
|
||||
|
||||
async handleAddAll(todos: Array<string>) {
|
||||
try {
|
||||
await Promise.all(todos.map((todo) => this.addMutation.mutateAsync(todo)))
|
||||
} catch (error) {
|
||||
console.error('Failed to add todos:', error)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
If some of the mutations above can fail independently of the others, and you want to know which ones did —
|
||||
rather than losing that information the moment the first one rejects — swap `Promise.all` for
|
||||
`Promise.allSettled`:
|
||||
```angular-ts
|
||||
@Component({
|
||||
selector: 'todos',
|
||||
template: `
|
||||
<button (click)="handleAddAll(['Todo 1', 'Todo 2', 'Todo 3'])">Add all</button>
|
||||
`,
|
||||
})
|
||||
export class Todos {
|
||||
readonly #queryClient = inject(QueryClient)
|
||||
|
||||
readonly addMutation = injectMutation(() => ({
|
||||
mutationFn: addTodo,
|
||||
onSuccess: () => this.#queryClient.invalidateQueries({ queryKey: ['todos'] }),
|
||||
}))
|
||||
|
||||
async handleAddAll(todos: Array<string>) {
|
||||
const addResults = await Promise.allSettled(
|
||||
todos.map((todo) => this.addMutation.mutateAsync(todo)),
|
||||
)
|
||||
|
||||
addResults.forEach((addResult, index) => {
|
||||
if (addResult.status === 'rejected') {
|
||||
console.error(`Failed to add "${todos[index]}":`, addResult.reason)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
```
|
||||
Reference in New Issue
Block a user