When it comes to loaders, take a load off your mind...
npm install @ngneat/loadoff
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();
}
}
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
.
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 })
}
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())
})
)
}
}
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)) {}
})
}
}
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.
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 [];
});
}
}
Thanks goes to these wonderful people (emoji key):
Netanel Basal 📖 🤔 |
This project follows the all-contributors specification. Contributions of any kind welcome!