joshcomley
joshcomley

Reputation: 28838

Applying a Resolve to root component in Angular2

In Angular2 we can use Resolve as follows:

import { UserResolver } from './resolvers/user.resolver.ts';

export const routes: RouterConfig = [
  {
    path: 'users/:id',
    component: UserComponent,
    resolve: {
      transaction: UserResolver
    }
  }
];

But how can I best apply a resolver to run on, for example, my app.component.ts? Perhaps when the website loads for the first time, no matter what page is first loaded, I'll always need to get the user data first (for example). So how can I have this resolver apply lower down the hierarchy of routes?

Upvotes: 8

Views: 5247

Answers (1)

AngularChef
AngularChef

Reputation: 14087

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.

Upvotes: 3

Related Questions