ngx-remotedata v8.0.0
RemoteData
Slaying a UI Antipattern with Angular.
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.
12 months ago
1 year ago
1 year ago
1 year ago
2 years ago
2 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
5 years ago
5 years ago
5 years ago