问题描述
有一个简单的(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效果顺序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!