@void-snippets/angular
injectMutations
create, update, and remove mutations with Signal-based status fields.
#What it does
Returns three mutation objects — create, update, and remove. When any mutation completes, TanStack Angular Query invalidates the cache and triggers a background refetch for all mounted list/get queries for this resource.
#Signature
typescript
contactResource.injectMutations(): VSAngularMutationsResult<Contact.Id, Contact.Detail, Contact.Apis.Create, Contact.Apis.Update>#Each mutation object
VSAngularMutationState:
| Field | Type | Description |
|---|---|---|
mutate(vars) | (vars: TVars) => void | Fire and forget. Great for delete buttons. |
mutateAsync(vars) | (vars: TVars) => Promise | Use with await for sequential control — close a modal only after success. |
isPending | Signal | true while in flight. Wire to a button's disabled and spinner. |
isSuccess | Signal | true after the last call succeeded. |
isError | Signal | true after the last call failed. |
error | Signal | The error from the last failed call. |
data | Signal | Server response from the last successful call. |
reset() | () => void | Resets isSuccess, isError, and error to idle. |
#The key pattern — await before closing a modal
typescript
@Component({
template: `
<button (click)="openCreate()">+ New Contact</button>
@for (contact of contacts.list(); track contact._id) {
<app-contact-row
[contact]="contact"
(delete)="mutations.remove.mutate(contact._id)"
/>
}
<app-contact-dialog
[open]="dialogOpen()"
[saving]="mutations.create.isPending() || mutations.update.isPending()"
(save)="onSave($event)"
/>
`,
})
export class ContactsComponent {
private contactResource = useContactResource();
contacts = this.contactResource.injectList();
mutations = this.contactResource.injectMutations();
dialogOpen = signal(false);
dialogData = signal<Contact.Base | null>(null);
async onSave(formData: Contact.Apis.Create | Contact.Apis.Update) {
try {
const existing = this.dialogData();
if (existing) {
await this.mutations.update.mutateAsync({ _id: existing._id, payload: formData as Contact.Apis.Update });
} else {
await this.mutations.create.mutateAsync(formData as Contact.Apis.Create);
}
// Only runs on success — modal closes, list refreshes automatically
this.dialogOpen.set(false);
} catch (err) {
// Modal stays open so the user can fix and retry
console.error(err);
}
}
}