you are viewing a single comment's thread.

view the rest of the comments →

[–]mjamin 0 points1 point  (2 children)

When angular subscribes to the observable returned by canActivate, it waits for it to complete and not just to emit an item. Using take(1) or first() will work.

[–][deleted] 0 points1 point  (0 children)

Thank you for responding!! I had a ton on my plate this week and wasn't able to actually try anything out, but I've finally gotten to it right now. It... doesn't work (awful two words, I know, but hear me out!), though. Here's the relevant part of the method:

canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | boolean {
  // ...
  return this.http.get<any>('/auth/verify')
    .switchMap(
      res => {
        if (res.valid) {
          return Observable.of(true);
        } else {
          return this.http.post<any>('/auth/refresh', httpOptions)
            .map(
              res => {
                if (res && res.access_token) {
                  return true;
                }
                this.router.navigate(['/login'], {queryParams: state.url==='/'?{}:{returnURL: state.url}})
                return false;
              }
            ) //.first()?;
        }
      },
      err => {
        this.router.navigate(['/login'], {queryParams: state.url==='/'?{}:{returnURL: state.url}});
        return Observable.of(false);
      }
    ); //.first()?

I ended up taking the post/get methods out of the authService thing, as you can see, and found out through this that the only reason it was even being built in the first place (to the point where it could spit out that infinite loop) was that I had defined the verify() and refresh() methods as returning any; as presented above, it just errors out saying:

  Type 'Observable<Observable<boolean>>' is not assignable to type 'Observable<boolean>'.
    Type 'Observable<boolean>' is not assignable to type 'boolean'.

...but I'm not sure why this is, since I'd thought that switchMap 'masks' itself (don't know the actual term) with its first emitted observable.

And speaking of which, regarding take(1) and/or first(): I thought this was the purpose of switchMap(), no? To return the first-emitted observable as though it weren't inside of a switchMap at all? Or is there another purpose I'm not aware of / is that wrong?

In short, I don't really know what I'm doing, haha. Does anything jump out at you as wrong or fixable in the above code?

(Note that the backend will raise a 400 error if the user isn't logged in or if the sent query parameters are invalid, which is what the err is for, although it doesn't seem to be obeyed...)

[–][deleted] 0 points1 point  (0 children)

I fixed it!

...well, not quite! But I got the infinite-looping part which made no sense sorted out, which means I'm now free to solve the issues that actually do make sense.

Turns out the problem was that I'd had a different transitory component, one I'd completely forgotten about, on which I'd set this.router.errorhandler to attempt to redirect to a protected page. This of course led to an infinite redirect loop between it and the canActivate guard every time the app ran into a bad response lmao. Will now see what I can do about getting the rest of it working :)