Angular 路由器防护和 ROUTER_NAVIGATION 效果顺序

Fel*_*lix 5 typescript ngrx ngrx-effects ngrx-store-4.0

有一个简单的(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(); }
}
Run Code Online (Sandbox Code Playgroud)

路由:

const routes: Routes = [
    { path: 'app-list', canActivate: [ContractsLoadedGuard], component: AppListComponent },
];
Run Code Online (Sandbox Code Playgroud)

最后还有一个由@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));
Run Code Online (Sandbox Code Playgroud)

不幸的是,当导航更改为/app-listngrx 效果时,首先执行(在守卫之前),因此数据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 */) 
Run Code Online (Sandbox Code Playgroud)

我不确定这是否足够好的解决方案。必须有更好的方法来做到这一点 - 不要复制有效的守卫功能。

总结一下:在应用程序 boostrap 上,我需要从后端获取一些数据 - contracts。如果用户导航到/app-list(立即重定向),则会从服务器获取其他数据 - 基于一些查询参数和contracts- ngrx 路由器ROUTER_NAVIGATION effect执行顺序在保护执行顺序之前。如何正确处理?

基于GitHub - state_management_ngrx4

Rup*_*ari 2

有一种方法可以实现这一目标。您可以在您的效果中订阅 Angular Router 的 ResolveEnd 事件https://angular.io/api/router/ResolveEnd,然后为 RESOLVE_END 调度您自己的操作,您可以在其中使用您的解析器/保护数据执行操作。

实际上,我在 ngrx/platform 中有一个 PR,其中 ngrx/router 将开箱即用地调度 NAVIGATE_RESOLVE_END 操作。我正在等待 ngrx 团队接受我的 PR。https://github.com/ngrx/platform/pull/524/

您可以订阅路由器事件并过滤它以获得解决结束并调度您自己的操作(称为 Router_Resove_End 操作等)。

this.router.events.filter(e => e instanceof ResolveEnd).subscribe(s => {
 // dispatch your own action here.
});
Run Code Online (Sandbox Code Playgroud)