Reputation: 51
With a hierarchical route structure, I would like to get the resolvers along a particular branch to execute in parallel.
Currently I have my routing setup like this:
app-routing.module.ts:
const routes: Routes = [
{
path: 'route1',
loadChildren: () =>
import('./route1/route1.module').then((m) => m.Route1Module),
},
];
route1-routing.module.ts:
const routes: Routes = [
{ path: '',
component: Route1Component,
resolve: {
route1: Route1Resolver
},
children: [{
path: 'subroute1',
loadChildren: () =>
import('../subroute1/subroute1.module').then((m) => m.Subroute1Module),
}]
}
];
subroute1-routing.module.ts:
const routes: Routes = [
{
path: '',
component: Subroute1Component,
resolve: { subroute1: SubRoute1Resolver },
},
];
And then just for illustration purposes we have the two resolvers with different delays:
export class Route1Resolver implements Resolve<any> {
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<any> {
console.log('Route1 starting')
return timer(6000).pipe(take(1), tap(_ => {console.log("Route1 finished")} ));
}
}
export class SubRoute1Resolver implements Resolve<any> {
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<any> {
console.log('SubRoute 1 started')
return timer(3000).pipe(take(1), tap(_ => {console.log("SubRoute1 finished")} ));
}
}
When I visit http://localhost:4200/route1/subroute1, and I'm watching the console, every time I see that the Route1 resolver has to finish before the SubRoute1 resolver can start.
Route1 starting
Route1 finished
SubRoute 1 started
SubRoute1 finished
The sequential execution of these resolvers introduces an undesirable delay. Ideally these two resolvers can execute in parallel, and once the last one finishes and all of the data is in, then Angular can move on to rendering what is in the <router-outlet>
.
Is there a way to have these resolvers execute in parallel?
<router-outlet>
to prematurely render when not all of the data is available.Upvotes: 0
Views: 396
Reputation: 51
I may have been thinking of this the wrong way. There are probably likely two cases here why we would want to load some kind of data asynchronously in an ancestor route:
It is non-critical data required by a sub-component in the ancestor component tree (in otherwords for a component outside of the <router-outlet>
). If this is the case then it could be that the responsibility of data fetching is delegated to the components, not a resolver in the routes. In this case "non-critical" means you would not interrupt the users navigation if the data was not there, to 404 for example.
It is critical data. In this case the descendent resolver (SubRoute1 in the example given) would have to bare some responsibility. Though the extent of that responsibility could be abstracted away:
Route1Resolver
can setup the Observable to do the data fetch, and then place it somewhere where it is accessible but will not be subscribed to by the framework. Either place it in a Service, or wrap the observable in an observable and return that so it is available through route data. Eg, return of(myDataFetchObsersable$)
SubRoute1Resolver
would be responsible for retrieving the observable from Route1Resolver
and integrating with it, probably with rxjs' combineLatest
.Upvotes: 0