简体   繁体   中英

CanActivate Guard doesn't seem to subscribe to observable

I have an angular application which has a number of steps to complete. Each step can only be done once and must have all previous steps complete. To achieve this I have added route guards to each route. The application makes a http request on start to check the status. However the route guard canActivate method doesn't seem to be subscribing to changes.

In the below example statusService updates the status which should trigger an update in the guards.

statusService

@Injectable({
  providedIn: 'root'
})
export class StatusService {

  private stepOneComplete: BehaviorSubject<boolean> = new BehaviorSubject(false);
  private stepTwoComplete: BehaviorSubject<boolean> = new BehaviorSubject(false);

  constructor(
    private http: HttpClient
  ) { }

  public getStepOneComplete(): Observable<boolean> {
    return this.stepOneComplete;
  };

  public updateStepOneComplete(newValue: boolean): void {
    this.stepOneComplete.next(newValue);
  };

  public initialize(): void {
    this.http.get(`${apiUrl}status`)
      .subscribe((data: any) => {
        this.stepOneComplete(data.stepOne);
      });
  };
};

stepOneGuard

@Injectable()
export class StepOneGuard implements CanActivate {

  constructor(
    private service: StatusService,
    private router: Router
  ) {}

  canActivate(): Observable<boolean> {
    return this.service.getStepOneComplete().pipe(
      tap(complete => {
        if(complete){
          this.router.navigate(['/step-two']);
        }
      }),
      map(complete => {
        return !complete;
      })
    );
  }
}

What I expect to happen is that after the initialize method runs and updates stepOneComplete then the router should navigate to step two. However no navigation occurs. If I put a console.log in the tap method of the guard it fires on initial load but not when stepOneComplete.next is called.

I think the answer is here:

public getStepOneComplete(): Observable<boolean> {
  return this.stepOneComplete.asObservable();
}

This is what I have in my own production code, works just fine.

You should not see a guard as a singleton that controls navigation. Its only purpose is to control whether the user can access a page or not.

I suggest you to have a state service that holds the state of your "wizard", and then you would simply check it in every guard. You shouldn't even need Subjects at all.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM