Skip to content
master
Go to file
Code

Latest commit

 

Git stats

Files

Permalink
Failed to load latest commit information.
Type
Name
Latest commit message
Commit time
 
 
 
 
e2e
 
 
 
 
src
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

README.md

RemoteData

Slaying a UI Antipattern with Angular.

Build Status npm version

Library inspired by Kris Jenkins blog post about How Elm slays a UI antipattern, which mixes pretty well with another article written by Scott Hurff about what he calls the UI Stack.

What we are trying to solve

You are making an API request, and you want to display different things based on the status of the request.

The Boolean approach

export interface SunriseSunset {
  isInProgress: boolean;
  error: string;
  data: {
    sunrise: string;
    sunset: string;
  };
}

Let’s see what each property means:

  • isInProgress: It‘s true while the remote data is being fetched.
  • error: It‘s either null (no errors) or any string (there are errors).
  • data: It’s either null (no data) or an object (there is data).

There are a few problems with this approach but the main one is that it is possible to create invalid states such:

{
  isInProgress: true,
  error: 'Fatal error',
  data: {
    sunrise: 'I am good data.',
    sunset: 'I am good data too!',
  }
}

Our template will have to use complex *ngIf statements to make sure that we are displaying precisely what we should.

The RemoteData approach

Instead of using a complex object we use a single data type to express all possible request states:

type RemoteData<T, E = string> =
  | NotAsked
  | InProgress<T>
  | Failure<E, T>
  | Success<T>;

This approach makes it impossible to create invalid states.

Installation

npm install --save ngx-remotedata

Basic Usage

// app.module.ts

import { RemoteDataModule } from 'ngx-remotedata';

@NgModule({
  imports: [
    // (...)
    RemoteDataModule
  ]
})
// app.component.ts

import { InProgress, NotAsked, Success, Failure } from 'ngx-remotedata';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html'
})
export class AppComponent {
  remoteData: RemoteData<string> = NotAsked.of();

  setNotAsked() {
    this.remoteData = NotAsked.of();
  }

  setInProgress() {
    this.remoteData = InProgress.of('In progress...');
  }

  setSuccess() {
    this.remoteData = Success.of('Success!');
  }

  setFailure() {
    this.remoteData = Failure.of('Wrong!');
  }
}
<!-- app.component.html -->

<ul>
  <li><button (click)="setNotAsked()">Not Asked</button></li>
  <li><button (click)="setInProgress()">InProgress</button></li>
  <li><button (click)="setSuccess()">Success</button></li>
  <li><button (click)="setFailure()">Failure</button></li>
</ul>

<hr />

<h4 *ngIf="remoteData | isNotAsked">Not Asked</h4>
<h4 *ngIf="remoteData | isInProgress">InProgress...</h4>
<h4 *ngIf="remoteData | isSuccess" style="color: green">
  {{ remoteData | successValue }}
</h4>
<h4 *ngIf="remoteData | isFailure" style="color: red">
  {{ remoteData | failureValue }}
</h4>

Some examples

Api

RemoteData

RemoteData<T, E = string>

RemoteData is used to annotate your request variables. It wraps all possible request states into one single union type. Use the parameters to specify:

  • T: The success value type.
  • E: The error value type (string by default).

NotAsked

NotAsked

When a RemoteData is an instance of the NotAsked class, it means that the request hasn't been made yet.

type User = { email: string };
const remoteData: RemoteData<User> = NotAsked.of();

InProgress

InProgress<T>

When a RemoteData is an instance of the InProgress class, it means that the request has been made, but it hasn't returned any data yet. The InProgress class can contain a value of the same T type as the Success class. Useful when you want to use the last Success value while the new data is being fetched.

type User = { email: string };
const remoteData: RemoteData<User> = InProgress.of({ email: 'john@doe.com' });

Success

Success<T>

When a RemoteData is an instance of the Success class, it means that the request has completed successfully and the new data (of type T) is available.

type User = { email: string };
const remoteData: RemoteData<User> = Success.of({ email: 'john@doe.com' });

Failure

Failure<E, T>

When a RemoteData is an instance of the Failure class, it means that the request has failed. You can get the error information (of type E) from the payload and. As with the InProgress class, Failure can optionally contain a value of the same T type as the Success class. Useful when you want to use the last Success value while displaying the failure message.

type User = { email: string };
const remoteData: RemoteData<User> = Failure.of('Something went wrong.');

The default type for errors is string, but you can also provide other types like Error:

type User = { email: string };
const remoteData: RemoteData<User, Error> = Failure.of(
  new Error('Something went wrong.')
);

Pipes

isNotAsked

isNotAsked | RemoteData<any> : boolean

Returns true when RemoteData is a NotAsked instance.

anyIsNotAsked

anyIsNotAsked | Observable<RemoteData<any>>[] : boolean

Returns true when any RemoteData<any>[] item is a NotAsked instance.

isInProgress

isInProgress | RemoteData<any> : boolean

Returns true when RemoteData is an InProgress instance.

anyIsInProgress

anyIsInProgress | Observable<RemoteData<any>>[] : boolean

Returns true when any RemoteData<any>[] item is an InProgress instance.

isFailure

isFailure | RemoteData<any> : boolean

Returns true when RemoteData is a Failure instance.

isSuccess

isSuccess | RemoteData<any> : boolean

Returns true when RemoteData is a Success instance.

hasValue

hasValue | RemoteData<any> : boolean

Returns true when RemoteData is a Success instance or is an InProgress or Failure instance with a value that is not null or undefined.

successValue

successValue | RemoteData<T> : (T | undefined)

Returns the Success payload (of type T) when RemoteData is a Success instance or undefined otherwise.

inProgressValue

inProgressValue | RemoteData<T> : (T | undefined)

Returns the InProgress payload (of type T) when RemoteData is an InProgress instance or undefined otherwise.

remoteDataValue

remoteDataValue | RemoteData<T> : (T | undefined)

Returns the InProgress, Failure or Success payload (of type T) when RemoteData is an InProgress, Failure or Success instance, returns undefined otherwise.

failureError

failureError | RemoteData<T, E> : (E | undefined)

Returns the Failure error payload (of type E) when RemoteData is a Failure instance or undefined otherwise.

failureValue

failureValue | RemoteData<T, E> : (T | undefined)

Returns the Failure payload (of type T) when RemoteData is a Failure instance or undefined otherwise.