本文介绍了角路由器防护和ROUTER_NAVIGATION效果顺序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有一个简单的(Angular 4)路由防护,它等待从后端加载一些数据:

There is a simple (Angular 4) route guard, which waits for some data to be loaded from backend:

@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 v4 ROUTER_NAVIGATION动作触发的@ ngrx/效果:

And finally there is an @ngrx/effects triggered by @ngrx/router-store v4 ROUTER_NAVIGATION action:

@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数据(这是后卫的工作):

Unfortunatelly when navigation changes to /app-list the ngrx effect is executed first (before guard) and thus the data state.contracts are not available yet. The guard has not been executed yet.I do have to add .combineLatest() Rx operator to wait for the contracts data in effect also (this is guard's job):

@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 */) 

我不确定这是否是一个好的解决方案.必须有更好的方法来做到这一点-不要复制有效的防护功能.

I'm not unsure if this is good solution enough. There must be a better way to do it - not duplicate the guard functionality in effect.

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

To summarize: On application boostrap, I need to fetch some data from backend - contracts. If an user navigates to /app-list (immediate redirect) there are other data fetched from server - based on some query params and contracts - the ngrx router ROUTER_NAVIGATION effect execution order is before the guard execution order. How to handle this properly?

基于 GitHub-state_management_ngrx4

推荐答案

有一种方法可以实现它.您可以订阅Angular Router的ResolveEnd事件 https://angular.io/api/router/ResolveEnd生效,然后为RESOLVE_END分派您自己的操作,您可以在其中使用解析程序/保护数据进行处理.

There is one way to achieve it. You can subscribe to the Angular Router's ResolveEnd event https://angular.io/api/router/ResolveEnd in your effect and then dispatch your own action for RESOLVE_END where you can do stuff with your resolver / guard data.

实际上,我在ngrx/platform中创建了一个PR,其中ngrx/router会立即提供NAVIGATE_RESOLVE_END操作.我正在等待ngrx团队接受我的PR. https://github.com/ngrx/platform/pull/524/

Actually there is an PR in ngrx/platform that I created where ngrx/router will dispatch NAVIGATE_RESOLVE_END action out of the box. I am waiting for ngrx team to accept my PR. https://github.com/ngrx/platform/pull/524/

您可以订阅路由器事件并将其过滤为解析结束,然后调度自己的操作,称为Router_Resove_End操作等.

You can subscribe to router events and filter it for the Resolve End and dispatch your own action call it Router_Resove_End action etc.

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

这篇关于角路由器防护和ROUTER_NAVIGATION效果顺序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-10 19:53