I have a side effect like this:
@Effect()
FetchAllOrders$ = this.actions$
.ofType(SalesOrderActions.FETCH_ALL_ORDERS)
.switchMap((action: Action) => {
return this.soApiService.getUsersSalesOrders(action.payload);
})
.map((salesOrders: ListDto<SalesOrderList>) => this.actions.fetchAllOrdersSuccess(salesOrders));
I would like to show a loading symbol at the start of the effect and hide it at the end.
I've created a separate set of Actions, Reducers and store state to handle showing the loading symbol.
export class BusyActions {
static SHOW_SPINNER = "SHOW_SPINNER";
static HIDE_SPINNER = "HIDE_SPINNER";
showSpinner(): Action {
return { type: BusyActions.SHOW_SPINNER };
}
hideSpinner(): Action {
return { type: BusyActions.HIDE_SPINNER };
}
export const BusyState: IBusyState = {
visible: false,
busy: false
};
I've done it this way because the loading state needs to be shared with other modules, states, etc.
How do i call my BusyActions from the side effect? I would need to call the SHOW_SPINNER at the start and HIDE_SPINNER at the end.
Have i done this correctly? Or is there a better way to handle this?
Let's take an example: If you want to fetch a user.
What I usually do for that:
- Dispatch an action FetchUser
- In the reducer, set a flag on users
: isUserFetching: true
- Catch that action within an effect
- Call what you want, a service for example
- When the service returns what he has fetched, map that to a success action: FetchUserSuccess
- If something went wrong, map the error to an error action: FetchUserError
- In your user reducer, if for FetchUserSuccess
do what you want + set isUserFetching: false
- In your user reducer, if for FetchUserError
do what you want + set isUserFetching: false
@Effect()
fetchUser$: Observable<Action> = this.actions$
.ofType(FetchUser)
.pipe(
switchMap(action =>
this.usersService.fetchUser(action.payload).pipe(
map(
res =>
new FetchUserSuccess({
id: action.payload.id,
data: res,
})
),
catchError((err: HttpErrorResponse) =>
of(new FetchUserError(action.payload))
)
)
)
);
Within your view you can select the good part of the store into a variable, let say isFetchingUser$
and do:
<div *ngIf="isFetchingUser$ | async; else #loadingUser">
Show the user here
</div>
<div loadingUser>
Fetching user information
</div>
To achieve this you can use this npm package https://www.npmjs.com/package/angular2-busy
After adding all the necessary module to use the package in your case you need to declare a variable
busy: Promise<any>;
or
busy: Subscription;
And then use this variable like below
this.busy = this.actions$
.ofType(SalesOrderActions.FETCH_ALL_ORDERS)
.switchMap((action: Action) => {
return this.soApiService.getUsersSalesOrders(action.payload);
})
.map((salesOrders: ListDto<SalesOrderList>) => this.actions.fetchAllOrdersSuccess(salesOrders));
If you want to use your busyActions class then you have to import this class into your component and create a private variable in the component constructor and call your desired action of the class where it is necessary. But to me it is better to use that above package which works very good.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With