UtilAdded in v15.5Optional

wrAction

One async write as signals: status, loading, value, error, a single-flight run(). Beside it, wrKeyedAction() for which row is pending and wrResourceValue() for a resource's value that never throws.

Usage

run() during a pending run starts nothing and returns the run in flight. It never rejects: a throw lands in error() and resolves undefined. reset() goes back to idle and drops a result still in flight.

import { wrAction } from 'ngwr/utils';

@Component({
  template: `
    <button wr-btn [loading]="save.loading()" (click)="save.run(draft())">Save</button>
    @if (save.status() === 'error') {
      <wr-alert type="danger">Could not save.</wr-alert>
    }
  `,
})
export class DraftEditor {
  private readonly api = inject(DraftApi);
  readonly draft = signal<Draft>({ title: '' });
  readonly save = wrAction((draft: Draft) => this.api.save(draft));
}

Which row is pending

wrKeyedAction() runs the same write per key, single-flight per key, so two rows run at once while one row cannot run twice. A key is kept only while it is pending.

import { wrKeyedAction } from 'ngwr/utils';

@Component({
  template: `
    @for (row of rows(); track row.id) {
      <button wr-btn size="sm" [loading]="remove.pending(row.id)" (click)="remove.run(row.id)">
        Remove
      </button>
    }
  `,
})
export class RowList {
  readonly remove = wrKeyedAction((id: string) => this.api.remove(id));
}

A resource's value that never throws

resource.value() throws in the error state and is undefined while new params load. wrResourceValue() reads the value when there is one, keeps the last settled value through a load, a reload and an error, and answers the fallback before anything settled. Takes resource(), rxResource() and httpResource().

import { httpResource } from '@angular/common/http';
import { wrResourceValue } from 'ngwr/utils';

@Component({
  template: `<wr-table [items]="rows()" [loading]="users.isLoading()" />`,
})
export class Users {
  readonly page = signal(1);
  readonly users = httpResource<User[]>(() => `/api/users?page=${this.page()}`);
  readonly rows = wrResourceValue(this.users, []);
}

API

NameDescriptionTypeDefault
wrAction(fn)Wraps fn in a WrAction: status (idle / pending / success / error), loading, the last value, the last error, run(arg) and reset(). Needs no injection context.<A, R>(fn: (arg: A) => Promise<R>) => WrAction<A, R>-
WrAction.run(arg)Starts the write, or returns the promise of the run in flight. Resolves with the result, or undefined when the call threw or reset() ran first. Never rejects.(arg: A) => Promise<R | undefined>-
WrAction.reset()Back to idle with value and error cleared. A run in flight is disowned: its result is dropped.() => void-
wrKeyedAction(fn)The row form: pending(key) as a reactive read, loading while any key runs, error of the most recently settled run, run(key, arg) single-flight per key, and reset().<K, A, R>(fn: (key: K, arg: A) => Promise<R>) => WrKeyedAction<K, A, R>-
wrResourceValue(resource, fallback)A read-only signal of the resource's value: the value when it has one, the last settled value while it loads, reloads or sits in error, and fallback before anything settled. Needs an injection context.<T>(resource: Resource<T | undefined>, fallback: T) => Signal<T>-