# 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.

Source: https://ngwr.dev/reference/utils/wr-action  
Kind: Util  
Added in v15.5  
Optional

## 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.

```angular-ts
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.

```angular-ts
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()`.

```angular-ts
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

| Name | Description | Type | Default |
| --- | --- | --- | --- |
| `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>` | `-` |
