有一个简单的(Angular 4)路由守卫,它等待从后端加载一些数据:
@Injectable()
export class ContractsLoadedGuard implements CanActivate {
constructor(private store: Store<State>) { }
waitForData(): Observable<boolean> {
return this.store.select(state => state.contracts)
.map(contractList => !!contractList)
.filter(loaded => loaded)
.take(1);
}
canActivate(): Observable<boolean> { return this.waitForData(); }
}
路由:
const routes: Routes = [
{ path: 'app-list', canActivate: [ContractsLoadedGuard], component: AppListComponent },
];
最后有一个由@ngrx/router-store v4ROUTER_NAVIGATION
动作触发的@ngrx/effects:
@Effect() routeChange$ = this.actions$
.ofType(ROUTER_NAVIGATION)
.filter((action: RouterNavigationAction) => action.payload.routerState.url.indexOf('/app-list') > -1)
.withLatestFrom(this.store.select(state => state.contracts))
.switchMap(([action, contracts]: ([RouterNavigationAction, ContractList])) =>
this.restClient.load(action.payload.routerState.queryParams, contract));
不幸的是,当导航更改为/app-list
ngrx 效果时首先执行(在警卫之前),因此数据state.contracts
尚不可用。守卫还没有被处决。
我还必须添加.combineLatest()
Rx 运算符来等待contracts
数据生效(这是警卫的工作):
@Effect() routeChange$ = this.actions$
.ofType(ROUTER_NAVIGATION)
.filter((action: RouterNavigationAction) => action.payload.routerState.url.indexOf('/app-list') > -1)
.combineLatest(this.contractListGuard.waitForContractsToLoad(), a => a) <- HERE
.withLatestFrom(this.store.select(state => state.contracts))
.switchMap(/* same here */)
我不确定这是否足够好的解决方案。必须有更好的方法来做到这一点 - 不要复制有效的保护功能。
总结一下:在应用程序 boostrap 上,我需要从后端获取一些数据 - contracts
。如果用户导航到/app-list
(立即重定向),则从服务器获取其他数据 - 基于一些查询参数和contracts
- ngrx 路由器ROUTER_NAVIGATION
effect
执行顺序在警卫执行顺序之前。如何正确处理?