Reputation: 1632
I don't know if this is a good practice or not though. But below is what I am trying to do:
I am having 2 lazy loaded modules: ManagementModule
and ConfigurationModule
, and the route config is as below:
const routes: Routes = [
{path: '', redirectTo: 'management', pathMatch: 'full'}, {
path: 'configuration',
loadChildren: './configuration/configuration.module#ConfigurationModule',
canLoad: [UnconfiguredGuard]
},
{
path: 'management',
loadChildren: './management/management.module#ManagementModule',
canLoad: [ConfiguredGuard]
}
]
Basically the idea was to check system status and redirect to different phases, eg. if sys is not configured yet, redirect to /configuration
, otherwise, redirect to /management
.
Before I added @ngrx/store
into the project, the two canLoad
guard are simple:
// ConfiguredGuard:
canLoad(route) {
return this.configService.isConfigured()
.do((configured: boolean) => {
if (!configured) {
// redirect to /configuration if unconfigured
this.router.navigate(['/configuration']);
}
})
}
Now I want to adopt all @ngrx/{store,effects,router-store} libs, and the above guard is then changed to:
canLoad(route) {
this.store.dispatch(new CheckInitStatus());
return this.store.select('initStatus')
.filter(s => s.checked) // check only when loaded
.map(s => s.status === 'initialized')
.catch(() => of(false));
}
of course, the side effect is defined:
@Effect()
check$: Observable<InitStatusAction> = this.actions$
.ofType<CheckInitStatus>(CHECK_INITSTATUS)
.mergeMap(() => this.fetchInitStatus())
.map(status => new InitStatusChecked({status, checked: true}))
.catch(e => of(new InitStatusCheckFailure(e)));
But the navigation was not happening, there's no ROUTER_NAVIGATION
action emitted. Is anything I missed here? And also I am wondering whether this is a good practice? I did find some examples of canActivate
guard usage, but none for canLoad
guard. Please help, thanks!
Upvotes: 3
Views: 1893
Reputation: 1632
I finally figured it out, after a whole day of debugging! The fix is quite simple though, add first()
or take(1)
into the operator chain after filter()
, I cannot express the feeling I have now...but I do realize that I need a mindset change for using RxJS properly.
canLoad(route) {
this.store.dispatch(new CheckInitStatus());
return this.store.select('initStatus')
.filter(s => s.checked) // check only when loaded
.first() // or equivalently take(1)
.map(s => s.status === 'initialized')
.catch(() => of(false));
}
I should read the examples of canActivate
more carefully, this take(1)/first()
operator is all there, for example: https://toddmotto.com/preloading-ngrx-store-route-guards
Upvotes: 9