0
votes

I'm trying to load some specific page data before actually displaying the page. I've managed to do this using an Angular Resolver. To keep this simple I'm basically dispatching an action and returning the success action in the resolve method.

@Injectable()
export class NotificationsResolver implements Resolve<Action> {
constructor(
    private _store: Store<fromRoot.State>,
    private _actions: Actions,
) { }

public resolve(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Action> {
    this._store.dispatch(new notificationActions.GetNotifications());
    return this._actions.ofType(NotificationActionTypes.GET_NOTIFICATIONS_SUCCESS).take(1);
}

}

In my effect I'm doing the following:

@Effect()
    getNotifications$ = this._actions$
        .ofType(NotificationActionTypes.GET_NOTIFICATIONS)
        .withLatestFrom(this._store$)
        .switchMap(([, storeState]): any => {
            if (storeState.notificationsState.notifications.length > 0) {
                return [new notificationActions.GetNotificationsSuccess(storeState.notificationsState.notifications)];
            }
            return this._apiClient.getNotifications(storeState.initState.organizationId)
                .map((notifications: Notification[]) => new notificationActions.GetNotificationsSuccess(notifications))
                .catch(error => of(new notificationActions.GetNotificationsFail(error)));
        });

Removing the if statement makes the whole piece work as it's supposed to, but I don't want to call the API each time the user navigates to this route. Basically, I'm checking my store to see if I already have a list of notifications in order to not make an API call twice. If I do, I return those, if the list is empty, I get them from my backend.

Everything works fine when I get the list from my backend, I get redirected to me/notifications where I'm displaying that list of notifications. However, when I get it from the ngrx store, although I see the actions dispatching as they should (GET_NOTIFICATIONS -> GET_NOTIFICATIONS_SUCCESS), I am not being redirected to me/notifications.

Attaching the API call method and the reducer for this action and the route:

 public getNotifications(organizationId: UUID): Observable<any> {
    const headers = new HttpHeaders()
        .set('Content-Type', 'application/json')
        .set('Authorization', `Bearer ${this._authService.getAccessToken()}`);
    return this._httpClient.get(`${this._baseUri}/organizations/${organizationId}/notifications`, { headers: headers });

case NotificationActionTypes.GET_NOTIFICATIONS_SUCCESS: {
            return Object.assign({}, state, {
                loading: false,
                notifications: [...action.payload],
            });
        }



{ path: 'notifications', component: NotificationsComponent, resolve: {notifications: NotificationsResolver } }

Any help would be great. Thanks

1

1 Answers

0
votes

I've managed to find a workaround for this problem. I've added a new property to my state called "loaded" which I initially set to false. On GetNotificationsSuccess I set it to true. This leads to the following change in the route Resolver.

public resolve(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
        this._store.dispatch(new notificationActions.GetNotifications());
        return this.waitForLoading()
            .pipe(
                switchMap(() => this.waitForLoading())
            );
    }

waitForLoading(): Observable<boolean> {
    return this._store.select(state => state.notificationsState.loaded)
        .pipe(
            filter(loaded => loaded),
            take(1)
        );
}

If anyone has a different solution or can tell my why the first example isn't working I'd be glad.