@ngneat/loadoff
v2.1.0
Published
<p align="center"> <img width="20%" height="20%" src="./logo.svg"> </p>
Downloads
10,790
Maintainers
Readme
When it comes to loaders, take a load off your mind...
Installation
npm install @ngneat/loadoff
Create a Loader
To create a loader, call the loadingFor
function and specify the loaders you want to create:
import { loadingFor } from '@ngneat/loadoff';
@Component({
template: `
<button>
Add
<spinner *ngIf="loader.add.inProgress$ | async"></spinner>
</button>
<button>
Edit
<spinner *ngIf="loader.edit.inProgress$ | async"></spinner>
</button>
<button>
Delete
<spinner *ngIf="loader.delete.inProgress$ | async"></spinner>
</button>
`
})
class UsersTableComponent {
loader = loadingFor('add', 'edit', 'delete');
add() {
this.service.add().pipe(
this.loader.add.track()
).subscribe();
}
edit() {
this.service.add().pipe(
this.loader.edit.track()
).subscribe();
}
delete() {
this.service.add().pipe(
this.loader.delete.track()
).subscribe();
}
}
Async State
AsyncState
provides a nice abstraction over async
observables. You can use the toAsyncState
operator to create an AsyncState
instance which exposes a loading
, error
, and res
state:
import { AsyncState, toAsyncState } from '@ngneat/loadoff';
@Component({
template: `
<ng-container *ngIf="users$ | async; let state">
<p *ngIf="state.loading">Loading....</p>
<p *ngIf="state.error">Error</p>
<p *ngIf="state.res">
{{ state.res | json }}
</p>
</ng-container>
`
})
class UsersComponent {
users$: Observable<AsyncState<Users>>;
ngOnInit() {
this.users$ = this.http.get<Users>('/users').pipe(
toAsyncState()
);
}
}
You can also use the *subscribe
directive instead of *ngIf
.
createAsyncState
You can use the createAsyncState
to manually create an instance of AsyncState
:
import { createAsyncState } from '@ngneat/loadoff';
class UsersComponent {
state = createAsyncState()
}
The initial state of AsyncState
instance is:
{
error: undefined,
res: undefined,
loading: true,
complete: false,
success: false,
};
You can always override it by passing a partial object to the createAsyncState
function:
import { createAsyncState } from '@ngneat/loadoff';
class UsersComponent {
state = createAsyncState({ loading: false, complete: true, res: data })
}
createSyncState
Sometimes there could be a more complex situation when you want to return a sync
state which means setting the loading
to false
and complete
to true
:
import { createSyncState, toAsyncState } from '@ngneat/loadoff';
class UsersComponent {
ngOnInit() {
source$.pipe(
switchMap((condition) => {
if(condition) {
return of(createSyncState(data));
}
return inner$.pipe(toAsyncState())
})
)
}
}
Helper Functions
import { isSuccess, hasError, isComplete, isLoading } from '@ngneat/loadoff';
class UsersComponent {
loading$ = combineLatest([asyncState, asyncState]).pipe(someLoading())
ngOnInit() {
this.http.get<Users>('/users').pipe(
toAsyncState()
).subscribe(res => {
if(isSuccess(res)) {}
if(hasError(res)) {}
if(isComplete(res)) {}
if(isLoading(res)) {}
})
}
}
retainResponse
Sometimes you want to retain the response while fetching a new value. This can be achieved with the retainResponse
operator.
import { toAsyncState, retainResponse } from '@ngneat/loadoff';
@Component({
template: `
<ng-container *ngIf="users$ | async; let state">
<p *ngIf="state.loading">Loading....</p>
<p *ngIf="state.error">Error</p>
<p *ngIf="state.res">
{{ state.res | json }}
</p>
</ng-container>
<button (click)='refresh$.next(true)'>Refresh</button>
`
})
class UsersComponent {
users$: Observable<AsyncState<Users>>;
refresh$ = new BehaviorSubject<boolean>(true);
ngOnInit() {
this.users$ = this.refresh$.pipe(
switchMap(() => this.http.get<Users>('/users').pipe(toAsyncState())),
retainResponse()
);
}
}
The retainResponse
operator accepts an optional startWithValue
parameter which you can use to initialize the stream with an alternative AsyncState
value.
Async Storage State
AsyncStore
provides the same functionality as AsyncState
, with the added ability of being writable
:
import { AsyncState, createAsyncStore } from '@ngneat/loadoff';
@Component({
template: `
<ng-container *ngIf="store.value$ | async; let state">
<p *ngIf="state.loading">Loading....</p>
<p *ngIf="state.error">Error</p>
<p *ngIf="state.res">
{{ state.res | json }}
</p>
</ng-container>
<button (click)="updateUsers()">Update Users</button>
`
})
class UsersComponent {
store = createAsyncStore<Users>();
ngOnInit() {
this.users$ = this.http.get<Users>('/users').pipe(
this.store.track()
);
}
updateUsers() {
this.store.update((users) => {
return [];
});
}
}
Contributors ✨
Thanks goes to these wonderful people (emoji key):
This project follows the all-contributors specification. Contributions of any kind welcome!