You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular 5:Service订阅变量未更新,路由守卫未执行Observable的map操作

Hey there! Let's break down what's going wrong here and fix it step by step.

The Core Issues in Your Code

  1. Cold Observable Behavior: Observables in RxJS are "cold" by default—meaning they won't execute unless you subscribe to them or return them to a system that will subscribe (like Angular's route guard system). In your current code, you call this.usrData.isProfileComplete() but never subscribe to it, so the map operator never runs.
  2. Incorrect Return Type: The canActivate method can return an Observable<boolean>, Promise<boolean>, or plain boolean. Your current logic mixes synchronous checks with unsubscribed asynchronous code, so Angular can't wait for the profile check to finish before deciding whether to activate the route.
  3. Inefficient Data Fetch: You're using list() to fetch all user data when you only need the single profileComplete field. This adds unnecessary complexity and data transfer.

Step 1: Fix the UserDataService

Let's simplify the isProfileComplete method to fetch just the specific field we need:

import { map } from 'rxjs/operators';

constructor(private afd: AngularFireDatabase, private authService: AuthService) { }

isProfileComplete(): Observable<boolean> {
  // Fetch only the profileComplete node instead of the entire user list
  return this.afd.object(`/users/${this.authService.uid}/profileComplete`)
    .valueChanges()
    .pipe(
      // Convert null/undefined to false (default to incomplete if field doesn't exist)
      map(completeStatus => !!completeStatus)
    );
}

Step 2: Rewrite the AuthGuard's canActivate Method

We need to return an Observable that handles the entire authentication + profile check flow, so Angular can properly wait for the result:

import { map, catchError } from 'rxjs/operators';
import { of } from 'rxjs';

constructor(private authService: AuthService, private router: Router, private usrData: UserDataService) {}

canActivate(
  route: ActivatedRouteSnapshot,
  state: RouterStateSnapshot
): Observable<boolean> | boolean {
  // First check if user is authenticated
  if (!this.authService.isAuthenticated()) {
    this.router.navigate(['login']);
    console.log('user is not logged in ');
    return false;
  }

  // Return the profile check observable so Angular can subscribe to it
  return this.usrData.isProfileComplete().pipe(
    map(isComplete => {
      if (isComplete) {
        console.log('user is logged in & data form completed');
        return true;
      } else {
        this.router.navigate(['data_form']);
        console.log('user logged in but not completed the form');
        return false;
      }
    }),
    // Handle errors (e.g., user node doesn't exist)
    catchError(() => {
      this.router.navigate(['data_form']);
      return of(false);
    })
  );
}

Key Explanations

  • Returning the Observable: By returning the isProfileComplete() stream (with operators), Angular automatically subscribes to it and waits for the result to decide route access.
  • Simpler Data Fetch: Using object() instead of list() lets us directly get the profileComplete value, avoiding the need to loop through list items.
  • Error Handling: The catchError operator ensures we handle any unexpected issues (like missing user data) by redirecting to the profile form.

内容的提问来源于stack exchange,提问作者sheeni

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 07:10:31