UNPKG

rxjs-loading-state

Version:

Eliminates manual state management for loading and error states by transforming Observables into a LoadingState

162 lines (161 loc) 5.04 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.LoadingStateMachine = void 0; const rxjs_1 = require("rxjs"); const loading_state_1 = require("./loading-state"); class IllegalStateTransitionError extends Error { constructor(message) { super(message); this.name = "IllegalStateTransitionError"; Object.setPrototypeOf(this, new.target.prototype); // restore prototype chain } } /** * Handles transitions between different loading state and holds the context data that is related to the current state. * @class LoadingStateMachine */ class LoadingStateMachine { constructor() { this._state$ = new rxjs_1.BehaviorSubject(loading_state_1.LoadingState.NotStarted); } /** * Creates a new observable that represents the current state of the machine * * @returns {Observable<LoadingState>} Observable that emits the machine state */ asObservable() { return this._state$.asObservable(); } /** * Data of the current state. Depending on the current state, this may be undefined. */ get data() { return this._data; } /** * Error of the current state. Depending on the current state, this may be undefined. */ get error() { return this._error; } /** * The current LoadingState */ get state() { return this._state$.getValue(); } /** * Update data while in loading state * @param {T} newData */ update(newData) { if (!this.isLoading()) { throw new Error(`Update is only allowed during ${loading_state_1.LoadingState.Loading} state`); } this._data = newData; this._state$.next(loading_state_1.LoadingState.Loading); } /** * Starts loading */ start() { if (this.isLoading()) { throw new IllegalStateTransitionError(`Transition from ${this.state} to ${loading_state_1.LoadingState.Loading} not allowed`); } this._state$.next(loading_state_1.LoadingState.Loading); } /** * Transition to success state * @param {T} data */ succeed(data) { if (!this.isLoading()) { throw new IllegalStateTransitionError(`Transition from ${this.state} to ${loading_state_1.LoadingState.Success} not allowed`); } this._data = data; this._error = undefined; this._state$.next(loading_state_1.LoadingState.Success); } /** * Transition to error state * @param {any} error */ fail(error) { if (!this.isLoading()) { throw new IllegalStateTransitionError(`Transition from ${this.state} to ${loading_state_1.LoadingState.Error} not allowed`); } this._data = undefined; this._error = error; this._state$.next(loading_state_1.LoadingState.Error); } /** * Resets machine to not started */ reset() { if (this.isNotStarted()) { throw new IllegalStateTransitionError(`Transition from ${this.state} to ${loading_state_1.LoadingState.NotStarted} not allowed`); } this._error = undefined; this._data = undefined; this._state$.next(loading_state_1.LoadingState.NotStarted); } /** * @returns {Boolean} True if machine if loading has not been started or reset */ isNotStarted() { return this.state === loading_state_1.LoadingState.NotStarted; } /** * @returns {Boolean} True if machine is in loading state */ isLoading() { return this.state === loading_state_1.LoadingState.Loading; } /** * * @returns {Boolean} True if machine is in error state */ isError() { return this.state === loading_state_1.LoadingState.Error; } /** * @returns {Boolean} True if machine is in success state */ isSuccess() { return this.state === loading_state_1.LoadingState.Success; } /** * Factory to create a new machine in error state * @param {any} error * @returns {LoadingStateMachine<T>} The new LoadingStateMachine */ static asError(error) { const state = new LoadingStateMachine(); state.start(); state.fail(error); return state; } /** * Factory to create a new machine in success state * @param {T} data * @returns {LoadingStateMachine<T>} The new LoadingStateMachine */ static asSuccess(data) { const state = new LoadingStateMachine(); state.start(); state.succeed(data); return state; } /** * Factory to create a new machine in loading state * @param {T | undefined} data * @returns {LoadingStateMachine<T>} The new LoadingStateMachine */ static asLoading(data = undefined) { const state = new LoadingStateMachine(); state.start(); state.update(data); return state; } } exports.LoadingStateMachine = LoadingStateMachine;