Frederico Jesus
Frederico Jesus

Reputation: 668

Rxjs chaining, how to?

The following code is what I have and it works.

canActivate(route: ActivatedRouteSnapshot): Observable<UrlTree | boolean> {
  return new Observable<UrlTree | boolean>((observer) => {
    this._authorizedStore
      .select(selectProfile)
      .pipe(take(1))
      .subscribe((profile) => {
        if (!profile) {
          this._authorizedStore.dispatch(
            AuthorizedActions.loadProfile({ userId: this._authenticationApi.getUser().id }),
          );
        }

        this._authorizedStore
          .select(selectAuthorizedState)
          .pipe(first((state) => !!state.profile))
          .subscribe((state) => {
            if (state.profile.profiles.length > 0) {
              observer.next(true);
            } else {
              observer.next(this.router.createUrlTree(['./settings']));
            }
            observer.complete();
          });
      });
  });
}

What I wanted was to figure out a better and prettier way to do the same thing. Basically I want to first check if I have a profile, if I don't have it I want to trigger the request and then wait. One thing to note, as you can see I'm using Ngrx, so if I don't take(1) at the beginning I would get an infinite loop (not profile, make request, not profile, make request...).

Any ideas?

Upvotes: 0

Views: 62

Answers (1)

Mike Jerred
Mike Jerred

Reputation: 10525

You can use tap and switchMap. Like this:

this._authorizedStore
  .select(selectProfile)
  .pipe(
    take(1),
    tap(profile => {
      if (!profile) {
        this._authorizedStore.dispatch(
          AuthorizedActions.loadProfile({ userId: this._authenticationApi.getUser().id }),
        );
      }
    }),
    switchMap(profile => this._authorizedStore.select(selectAuthorizedState).pipe(first(state => !!state.profile)))
  )
  .subscribe(state => {
    if (state.profile.profiles.length > 0) {
      observer.next(true);
    } else {
      observer.next(this.router.createUrlTree(['./settings']));
    }
    observer.complete();
  });

You can also shorten your whole code to this:

canActivate(route: ActivatedRouteSnapshot): Observable<UrlTree | boolean> {
  return this._authorizedStore
    .select(selectProfile)
    .pipe(
      take(1),
      tap(profile => {
        if (!profile) {
          this._authorizedStore.dispatch(
            AuthorizedActions.loadProfile({ userId: this._authenticationApi.getUser().id }),
          );
        }
      }),
      switchMap(profile => this._authorizedStore.select(selectAuthorizedState)),
      first(state => !!state.profile),
      map(state => state.profile.profiles.length > 0 ? true : this.router.createUrlTree(['./settings']))
    );
}

Upvotes: 2

Related Questions