# Load State

> One wrapper for a screen that loads: the skeleton, the failure with a retry, the empty slot or the content.

Source: https://ngwr.dev/reference/components/load-state  
Kind: Component  
Added in v15.6

## Installation

Import the class, and `@use` the entry point in your global styles. Nothing warns you when the `@use` is missing.

```typescript
import { Component } from '@angular/core';
import { WrLoadState, WrLoadStateContent, WrLoadStateEmpty, WrLoadStateError, WrLoadStateLoading } from 'ngwr/load-state';

@Component({ imports: [WrLoadState, WrLoadStateContent, WrLoadStateEmpty, WrLoadStateError, WrLoadStateLoading] })
export class MyComponent {}
```

```scss
@use 'ngwr/load-state';
```

## Basic usage

Give it a `resource` and a content template. The content is created once the value is ready; a reload keeps it on screen and marks the wrapper busy.

```angular-html
import { httpResource } from '@angular/common/http';

@Component({
  imports: [WrLoadState, WrLoadStateContent, WrList, WrListItem],
  template: `
    <wr-load-state [resource]="orders">
      <ng-template wrLoadStateContent [wrLoadStateContentOf]="orders" let-orders>
        <wr-list>
          @for (order of orders; track order.id) {
            <wr-list-item>{{ order.id }}</wr-list-item>
          }
        </wr-list>
      </ng-template>
    </wr-load-state>
  `,
})
export class Orders {
  readonly orders = httpResource<Order[]>(() => '/api/orders');
}
```

```angular-ts
import { Component } from '@angular/core';

import { WrList, WrListItem } from 'ngwr/list';
import { WrLoadState, WrLoadStateContent } from 'ngwr/load-state';

/**
 * Basic usage
 */
@Component({
  selector: 'load-state-basic-usage-example',
  templateUrl: './load-state-basic-usage-example.html',
  imports: [WrList, WrListItem, WrLoadState, WrLoadStateContent],
})
export class LoadStateBasicUsageExample {}
```

## Status

Without a resource the app sets `status`. The retry button emits `(retry)`; answer it by loading again.

```angular-html
<wr-load-state [status]="status()" (retry)="load()">
  <ng-template wrLoadStateContent>Loaded.</ng-template>
</wr-load-state>
```

```angular-ts
import { Component, signal } from '@angular/core';

import { WrLoadState, WrLoadStateContent } from 'ngwr/load-state';

/**
 * Status
 */
@Component({
  selector: 'load-state-status-example',
  templateUrl: './load-state-status-example.html',
  imports: [WrLoadState, WrLoadStateContent],
})
export class LoadStateStatusExample {
  // Stubs. The page owned these values; the snippet shows the markup
  // that reads them, not where they come from.
  protected readonly load = signal<any>([]);
  protected readonly status = signal<any>([]);
}
```

## Templates

Each part is a template: `wrLoadStateLoading`, `wrLoadStateError` and `wrLoadStateEmpty` replace the defaults. The error template gets the error, `retry()` and `retrying`.

```angular-html
<wr-load-state [resource]="orders">
  <ng-template wrLoadStateLoading><wr-spinner /></ng-template>
  <ng-template wrLoadStateError let-error let-retry="retry" let-retrying="retrying">
    <wr-alert type="danger" title="Could not load orders" [message]="error.message">
      <wr-btn wrAlertActions size="sm" [loading]="retrying" (click)="retry()">Try again</wr-btn>
    </wr-alert>
  </ng-template>
  <ng-template wrLoadStateEmpty>
    <wr-empty title="No orders yet"><wr-btn wrEmptyActions size="sm">Create one</wr-btn></wr-empty>
  </ng-template>
  <ng-template wrLoadStateContent [wrLoadStateContentOf]="orders" let-orders>...</ng-template>
</wr-load-state>
```

```angular-ts
import { Component } from '@angular/core';

import { WrAlert } from 'ngwr/alert';
import { WrButton } from 'ngwr/button';
import { WrEmpty } from 'ngwr/empty';
import { WrLoadState, WrLoadStateContent, WrLoadStateEmpty, WrLoadStateError, WrLoadStateLoading } from 'ngwr/load-state';
import { WrSpinner } from 'ngwr/spinner';

/**
 * Templates
 */
@Component({
  selector: 'load-state-templates-example',
  templateUrl: './load-state-templates-example.html',
  imports: [WrAlert, WrButton, WrEmpty, WrLoadState, WrLoadStateContent, WrLoadStateEmpty, WrLoadStateError, WrLoadStateLoading, WrSpinner],
})
export class LoadStateTemplatesExample {}
```

## What is empty

`isEmpty` decides between the empty slot and the content. The default is `null`, `undefined` and an empty array.

```angular-html
<wr-load-state [resource]="page" [isEmpty]="v => !v || v.items.length === 0">
```

## States

What each resource status draws.

| `resource.status()` | Drawn |
| --- | --- |
| `loading` | The skeleton. |
| `reloading` | What was on screen, marked busy. After a failed load, the failure with its button busy. The skeleton when there is no value yet. |
| `error` | The failure. Its title is announced once, politely. |
| `resolved`, `local` | The empty slot when `isEmpty(value)`, else the content. |
| `idle` | The content or the empty slot, by `isEmpty`: nothing was asked for, so nothing loads. |

## API

| Name | Description | Type | Default |
| --- | --- | --- | --- |
| `status` | The state, when the app decides it. Ignored while `resource` is set. | `WrLoadStateStatus \| null` | `null` |
| `resource` | The resource to read the state from: `resource()`, `rxResource()` and `httpResource()` alike. The retry button calls its `reload()`. | `Resource<T \| undefined> \| null` | `null` |
| `isEmpty` | Decides whether a settled value shows the empty slot instead of the content. The default is empty for `null`, `undefined` and an empty array. | `(value: T \| undefined) => boolean` | `isEmptyValue` |
| `lines` | How many lines the default skeleton draws. | `number` | `3` |
| `errorLabel` | The failure's title. Falls back to `loadState.failed`, then `'Could not load'`. | `string \| null` | `null` |
| `retryLabel` | The retry button's label. Falls back to `loadState.retry`, then `'Try again'`. | `string \| null` | `null` |
| `emptyLabel` | The default empty slot's title. Falls back to `empty.noData` through `<wr-empty>`. | `string \| null` | `null` |
| `(retry)` | Emitted when the retry button is pressed, once per press that starts a retry. With a `resource`, `reload()` has been called as well. | `void` | — |

## Templates API

| Name | Description | Type | Default |
| --- | --- | --- | --- |
| `[wrLoadStateContent]` | On an `<ng-template>`: the content, created once ready. Import `WrLoadStateContent`. | `directive` | `-` |
| `[wrLoadStateContentOf]` | The resource, for the type checker only: types `let-value`. Bind the same resource as `[resource]`. | `Resource<T \| undefined> \| null \| undefined` | — |
| `let-value` | The resource's value. `undefined` when driven by `status`. | `T` | `-` |
| `let-reloading="reloading"` | A reload is in flight behind the content. | `boolean` | `-` |
| `[wrLoadStateLoading]` | On an `<ng-template>`: replaces the default skeleton. Import `WrLoadStateLoading`. | `directive` | `-` |
| `[wrLoadStateError]` | On an `<ng-template>`: replaces the default failure. Import `WrLoadStateError`. | `directive` | `-` |
| `let-error` | `resource.error()`. `undefined` when driven by `status`. | `Error \| undefined` | `-` |
| `let-retry="retry"` | Reloads the resource and emits `retry`. Does nothing while one is in flight. | `() => void` | `-` |
| `let-retrying="retrying"` | A retry is in flight. | `boolean` | `-` |
| `[wrLoadStateEmpty]` | On an `<ng-template>`: replaces the default `<wr-empty>`. Import `WrLoadStateEmpty`. | `directive` | `-` |

## CSS variables

Set these on the element itself, with a rule more specific than its Declared on selector. In a global stylesheet, put a class of yours on an ancestor it really has: `<body>` for an overlay panel, which renders outside your markup. In a component stylesheet the selector alone works, but only for an element in that component's own template. A value on a wrapper or `:root` is shadowed, because `ngwr/load-state` declares each default on its own element.

| Variable | Default | Declared on |
| --- | --- | --- |
| `--wr-load-state-error-padding-x` | `var(--wr-space-lg)` | `.wr-load-state` |
| `--wr-load-state-error-padding-y` | `var(--wr-space-xl)` | `.wr-load-state` |
| `--wr-load-state-error-title-font-size` | `var(--wr-text-base)` | `.wr-load-state` |

## Dependencies

| Built on | [Button](https://ngwr.dev/reference/components/button), [Empty](https://ngwr.dev/reference/components/empty), [Result](https://ngwr.dev/reference/components/result), [Skeleton](https://ngwr.dev/reference/components/skeleton) |
| --- | --- |

## See also

- [Skeleton](https://ngwr.dev/reference/components/skeleton) — A placeholder block shown while content loads.
- [Result](https://ngwr.dev/reference/components/result) — A full-size outcome screen, with ready-made 404, 403 and 500 pages.
- [Empty](https://ngwr.dev/reference/components/empty) — A placeholder for a view with no data.
- [Alert](https://ngwr.dev/reference/components/alert) — An inline status message.
- [wrAction](https://ngwr.dev/reference/utils/wr-action) — One async write as signals: status, loading, value, error, a single-flight run().
- [Button](https://ngwr.dev/reference/components/button) — A button for an action or a link.
- [List](https://ngwr.dev/reference/components/list) — A list of rows with leading, body and trailing slots.
- [Spinner](https://ngwr.dev/reference/components/spinner) — An inline loading indicator.
