@void-snippets/angular
Optimistic Updates
Cache transforms with rollback, effectiveBase stacking, and lifecycle hooks — identical semantics to React.
#What it does
Works identically to the React version — the same WeakMap-based stack, the same rollback-and-replay semantics. Configure the handlers once in createResourceInject and every mutation from injectMutations picks them up automatically.
#Configuration
typescript
export function useContactResource() {
const service = inject(ContactsService);
return createResourceInject('contacts', service, {
optimistic: {
// Applied immediately when update.mutate() fires — before the API responds
update: (cache, { _id, payload }) =>
cache.map((c) => (c._id === _id ? { ...c, ...payload } : c)),
// Item disappears instantly — restored automatically on API error
remove: (cache, id) =>
cache.filter((c) => c._id !== id),
// New item appears at top with a temporary ID
create: (cache, { payload, tempId }) => [
{ ...payload, _id: tempId as Contact.Id },
...cache,
],
// Only fires after rollback is complete — cache is already correct
onError: (err, op) => {
console.error(`Optimistic ${op.kind} failed, rolled back:`, err.message);
},
onSuccess: (op) => {
if (op.kind === 'create') analytics.track('contact_created');
},
},
});
}#Handler reference
| Handler | Fires on | Signature |
|---|---|---|
create | create.mutate() | (cache, { payload, tempId }) => TBase[] |
update | update.mutate() | (cache, { _id, payload }) => TBase[] |
updateSingle | update.mutate() (overrides the default shallow-merge for injectGet) | (current, payload) => TDetail |
remove | remove.mutate() | (cache, id) => TBase[] |
onError | Any mutation failure, after rollback completes | (error, operation) => void |
onSuccess | Any mutation success, after effectiveBase advances | (operation) => void |
#Concurrent rollback
The library maintains an ordered stack of every in-flight mutation and a "before" snapshot of the cache. If you delete item A, rename item B, and create item C concurrently, and B's rename fails:
- B is removed from the pending stack
- The cache is restored to the original snapshot
- A's delete and C's create are replayed in order
None of A's or C's changes are lost.