【问题标题】:Delay canActivate call when page refreshes in order to wait for the data to load页面刷新时延迟canActivate调用以等待数据加载
【发布时间】:2021-11-10 15:21:54
【问题描述】:

当我重新加载我的页面时,它总是转到空白页面而不是同一页面。这背后的原因是一旦用户刷新页面就会调用 canActivate 方法,该方法正在检查用户的权限,并且无法立即获取用户数据。用户数据会在几秒钟后出现。 有什么办法可以让 canActivate 方法等到数据完成?我一直在浏览 RxJS 的页面,但不知道该怎么做。 有人可以给我建议吗?

  constructor(private router: Router, private userDataService: UserDataService) {
    userDataService.userData$.subscribe(
      (data: User) => {
        this.userData = userData --> comes after some seconds
      }
    );
  }

  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot):         
     Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree 
  {
    const result = this.getUserData(route);
    if (!result) {
      this.blankPage();
    }
    return result;
  }


public getUserData(): Observable<boolean> {
    if (this.userData) {
        check for permissions...
        return of(true);    
    }
    return of(false);
}

userdata.service.ts:

  userDataSubscription: Subscription;
  userData: BehaviorSubject<User> = new BehaviorSubject<User>(null);
  public userData$: Observable<User> = this.userData.asObservable();
  
  
  private getUserData(): void {
    const userData$ = new Observable(
      subscriber => subscriber.next(new User())
    ).pipe(
      delay(1000),
      mergeMap((model: User) => this.getUserInfo(model)),
      mergeMap((model: User) => this.getUserPermission(model)),
      catchError((err, caught) => {
        console.error('failed')
        return caught;
      })
    );
    this.userContextDataSubscription = userData$.subscribe(
      (data: User) => {
        this.userData,next(model);
      },
      () => console.error('failed')
    );
  }

【问题讨论】:

  • “同一页面”在您点击(硬)刷新后不再存在。从那时起,浏览器将再次负责并显示一个空白页面,直到您的应用程序为其提供最初显示的内容。您最好的选择似乎是在加载 Angular 应用程序(或任何类型的路线)之前一直显示的加载屏幕。
  • @PhilippMeissner 感谢您的回复。无论如何我都在显示 loadinScreen 但是在加载完成后它将是空白的。这就是为什么它不会回到我的旧路线。它转到 localhost:4200/#/ 而不是 localhost:4200/#/my-comp
  • 乍一看,我注意到您手动订阅了 observable。不需要 - 只需让您的 canActivate 返回一个解析为 boolean 的 observable。比如:gist.github.com/PhilippMeissner/…
  • @PhilippMeissner。让我试试这个..
  • @PhilippMeissner 刷新后还是去localhost:4200/#/

标签: angular rxjs angular-ui-router canactivate


【解决方案1】:

您可能想在这里使用 Angular resolver 而不是守卫。解析器确保数据在路由加载之前可用和加载。

有很多有用的教程,只需搜索“Angular Resolver”即可。

解析器返回一个 Observable。您可能想要使用 RxJS 过滤器和 take(1) 运算符。像这样的:

resolve(
  route: ActivatedRouteSnapshot,
  state: RouterStateSnapshot
): Observable<any>|Promise<any>|any {
  return this.service.getMyData(route.paramMap.get('id')).pipe(
    filter(x => !!x),
    take(1)
  )
}

此处的过滤器可确保数据是真实值。然后 take(1) 基本上说我得到了我需要的东西。一切顺利。

【讨论】:

  • 非常感谢,但很遗憾,我无法使用 Resolver,但我会通过它来理解
【解决方案2】:

canActive 是一个异步方法,这意味着您可以返回 Observeble 或 Promise,并且在 Observable/Promise 解决之前不会加载路由 这是一个正确的canActivate用法示例:

     canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot):         
         Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree 
      {
        return this.userDataService.userData$
          .pipe(take(1))
          .pipe(map(user => {
            let result: boolean
            // check your permissions
            if (!result) {
               this.redirectToBlankPage();
               return false;
             }
             return result;
          }));
      }

【讨论】:

  • 你的意思是我需要从构造函数中删除我的订阅并将其放入 canActivate 方法中?
  • @Radiant 你不需要在构造函数中订阅并将结果保存到类字段,因为用户数据可以在canActivate 执行后解析,所以当canActivate 被调用时,userData 是对你来说总是空的,并且总是会调用 blankPage() (如果我是正确的,这是你的问题)
  • 正是...当我重新加载页面时,userData 始终为空/未定义/空,几秒钟后,它就来了。同时 canActivate 已经得到 false 作为响应,并且路由转到空白页面,并且 url 是 localhost:4200/#/ 而不是 localhost:4200/#/my-comp
  • @icekson..根据您的回答,它不再显示空白页面,而是显示没有应用保安人员的页面。这可能有效,但有什么方法可以等待 userData 到来,然后再次加载同一页面而不是其他页面?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-27
  • 2020-07-20
相关资源
最近更新 更多