Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 293
joshcomley Avatar asked Feb 23 '17 17:02

joshcomley


People also ask

What is a route resolver?

Angular Route Resolver is used for pre-fetching some of the data when the user is navigating from one route to another. It can be defined as a smooth approach for enhancing user experience by loading data before the user navigates to a particular component.

Which of the below is used to specify the root component to be loaded?

html file you must specify the root component using it's selector (usually app-root ).

Is the root component of an Angular application?

The root component that Angular creates and inserts into the index. html host web page. The default application created by the Angular CLI only has one component, AppComponent , so it is in both the declarations and the bootstrap arrays.


1 Answers

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.

like image 174
AngularChef Avatar answered Oct 12 '22 23:10

AngularChef