I've been wondering about the same thing.
Turns out that if the initial request to the site is for a path which has one of its components guarded by a resolve, the resolve will run before any component in the tree is instantiated. Including AppComponent
.
Now the problem is that AppComponent
itself is NOT a routed component and as such it cannot access the resolved data. Maybe you could inject ActivatedRoute
into AppComponent
and access the data via the current route's children
but it seems hackish.
What I typically do is set up a resolve (or CanActivate
guard) at the root of my route hierarchy to fetch that initial data. The data itself is returned by a service and wrapped inside a ReplaySubject
. This guarantees that 1) the data will be shared among all subscribers; 2) the code fetching the data will only be executed once.
In other words:
- I use an observable to fetch the async data once and share it among all the parts of my app that need it.
- I rely on the route system to trigger the execution of that observable as early as possible in the app lifecycle.
(But I'm not using the route system to fetch the data and share it.)
Update to answer the comments:
You have to introduce a dummy parent route to support the guard, for instance:
const routes: Routes = [
{
path: '', // This is the "root route"
component: PageShellComponent,
canActivate: [AuthGuard],
children: [
{ path: 'home', component: PageHomeComponent },
{ path: 'inbox', component: PageInboxComponent },
{ path: 'settings', component: PageSettingsComponent }
]
},
];
The parent route is the "root of the my route hierarchy" and its guard AuthGuard
gets executed for ALL child routes in the application. As you can see, the parent route has an empty path and PageShellComponent
's template only contains <router-outlet></router-outlet>
. The sole purpose of this route is to support the guard(s).
I should add it doesn't feel very idiomatic and I'm not sure this is the best way to go.