在 Angular 路由守卫中等待 return 的值

Waiting for a value to return in Angular route guards

我在 Angular 中使用 Ionic。 在我的一个路由守卫中,我需要查看是否创建了一个 firestore 文档以及 return 它的一个布尔值,这需要一些时间才能从服务器获得响应,但是路由守卫不会等待为return的值并正常运行,所以页面没有被保护! 我怎样才能让路由守卫等待价值? 或者,return路由守卫运行前的值? 这是我向 firestore 发送请求的地方:

export class FirebaseService {

  ex: Promise<boolean>;
  categoryDone: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
  constructor(private afs: AngularFirestore) {
    this.ex = new Promise((resolve) => {
          this.afs.collection('users').doc(this.user.uid).collection('categories').get().toPromise().then(
            data => {
              if (data.size > 0) {
                resolve(true)
              } else {
                resolve(false)
              }
            }
          )
        })
        this.ex.then(data=>{
          if (data) {
            this.categoryDone.next(true)
          } else {
            this.categoryDone.next(false)
          }
        })
  }

这是我的路由守卫代码,我将它用于我的页面:

export class CategoryDoneGuard implements CanActivate {
  categoryDone: boolean;
  constructor(private router: Router, private firebaseService: FirebaseService) {
    this.firebaseService.categoryDone.asObservable().subscribe(
      categoryDone => this.categoryDone = categoryDone
    )
  }
  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean> | boolean {
      console.log(this.categoryDone,"Category Done VAriable in CategoryDoneGuard")
      setTimeout(() => {
        console.log(this.categoryDone,"Catgeory") //true because i waited 1 second
      }, 1000);
    if (!this.categoryDone) { //variable is undefined here 
      console.log('You are in InfoDoneGuard')
      return true
    }
    this.router.navigate(['tabs/tab-profile'])
    return false
  }

}

不要 return 布尔值,return Observable!

导出class CategoryDoneGuard 实现 CanActivate {

      constructor(
        private router: Router,
        private firebaseService: FirebaseService
      ) { }

      canActivate(
        next: ActivatedRouteSnapshot,
        state: RouterStateSnapshot,
      ): Observable<boolean> {

        return this.firebaseService.categoryDone.asObservable().pipe(
          map(Boolean),
          tap(b => if (!b) this.router.navigate(['tabs/tab-profile'] ),
        );
     }

就像在其他答案中一样,auth guard 可以接受布尔值、可观察值或布尔值或 urltree 的承诺。但我会稍微重组整个服务功能,除非你需要 categoryDone 做其他事情,但如果你需要的话,你可以在你的服务中添加它。

但就您的服务目前而言,您在调用 toPromise() 的同时也创建了一个新的承诺,这实际上没有任何意义。

我会做...

服务:

// please choose a more suitable name :D 
getBool() {
  return this.afs.collection('users').doc(this.user.uid).collection('categories').get().pipe(
    map(data => data.size > 0),
    // if you need
    // tap(bool => this.categoryDone.next(bool))
  )
}

可以激活:

canActivate(...): Observable<boolean> {
  return this.firebaseService.getBool().pipe(
    map(bool => {
      if (bool) {
        return true;
      }
      this.router.navigate(['tabs/tab-profile'])
      return false;
    })
  )
}

但是如果 categoryDone 在您的应用程序中对您来说必不可少,您也可以像 MoxxiManagarm 的回答一样在 authguard 中订阅它。无论如何,我会重组 firebase 查询以删除 promise 内容。