Route Guard 加载 ngrx 存储数据仅在第二次单击后导航到受保护的路由

Route Guard loading ngrx store data only navigates to protected route after second click

为了在加载实际组件之前将数据从后端加载到我的 ngrx 存储中,我在路由的 canActivate 属性中使用了路由保护。

{path: 'my-route', component: MyRouteComponent, canActivate: [LoadDataGuardService]}

如果相应的数据已经可用,守卫应该检查商店。如果没有,它应该从后端加载到商店中。一旦数据在存储中,就应该打开路由(第一次点击)。这是我的 Guard 的 canActivate 方法。

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
    const loadedTasks = this.store.pipe(select(selectTaskMap))
      .pipe(map(taskMap => Object.keys(taskMap).length > 0));

    loadedTasks
      .pipe(
        take(1),
        filter(loaded => !loaded),
        map(() => this.store.dispatch(GetTasks())))
      .subscribe(() => this.store);

    return loadedTasks
      .pipe(take(1));
  }

在第一次点击时将数据加载到商店中。但是如果必须加载数据,我必须再次单击 link 才能导航到所需的视图。似乎第一次点击只加载数据,但在成功加载数据后没有 return 一个 True 的 Observable。

如何调整代码将数据加载到store中,并在第一次点击数据到store时立即打开路由?

编辑:

这里有一个用于复制的 stackblitz 工作示例:Stackblitz Link
可以清楚的看到,第二次点击 Activate Route link.
后,路由组件的内容才显示出来 为了在测试时清除商店,我添加了一个按钮。

看来问题是第一次任务还没有加载。

尝试将 first 移到 filter 之后。

import {Injectable} from '@angular/core';
import {ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot} from '@angular/router';
import {Store, select } from '@ngrx/store';
import {filter, tap, map, take} from 'rxjs/operators';
import { selectEntityMap } from './store/selectors/entity.selectors';
import { AppState } from './store/state/app.state';
import { GetEntity } from './store/actions/entity.actions';

@Injectable({
  providedIn: 'root'
})
export class LoadDataGuardService implements CanActivate {

  constructor(public router: Router, private store: Store<AppState>) {
  }

  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
    return this.store.pipe(select(selectEntityMap)).pipe(
      map(taskMap => Object.keys(taskMap).length > 0),
       tap(loaded => {
        if (!loaded) { // checking if we need to dispatch the action.
          this.store.dispatch(GetEntity());
        }
      }),
      filter(loaded => !!loaded), // waiting until the tasks have been loaded.
      take(1),
    );
  }
}