13

I'm trying to resolve data before navigating to children routes as i have to use that data in children guard. The issue is parent resolver, resolves data after the child guard is fired. Resolver takes long time to resolve data

// app.module.ts
const appRoutes: Routes = [
  { path: 'login', component: LoginComponent },
  {
    path: '',
    component: SiteLayoutComponent,
    children: [
      { path: '', redirectTo: 'warehouse', pathMatch: 'full' },
      {
        path: 'warehouse',
        loadChildren: './warehouse/warehouse.module#WarehouseModule'
        // loadChildren: () => WarehouseModule
      }
    ],
    canActivate: [AuthGuard],
    resolve: {
      Site: SiteResolver // should be resolved before the guard is invoked.
    }
  },
  { path: '**', component: PageNotFoundComponent }
];

// warehouse.module.ts
const appRoutes: Routes = [

    { path: '', redirectTo: 'cash', pathMatch: 'full' },
    { path: 'cash', component: CashComponent, canActivate: [RouteGuard] // should be invoked after the parent resolver resloves th data }

];

Here, the parent resolver i.e. SiteResolver resolves after the child guard i.e. RouteGuard is invoked. What i want is SiteResolver to resolve data first and then RouteGuard should fire, how can i achieve that ?

Asad Shah
  • 771
  • 2
  • 8
  • 22
  • 1
    As you can see here: https://angular.io/guide/router#resolve-guard, the resolver is considered a guard itself but has a minor priority compared to the route guard. So the order is not interchangeable. First comes the route guard and then the resolver. –  Mar 22 '18 at 16:58
  • 1
    This happens for me when i refresh the browser having the child route. Can anyone help in this – Renil Babu Aug 10 '18 at 05:15

3 Answers3

5

I am not sure if this is the correct method. But after going through a lot of angular issues , i found a workaround.

Instead of resolve , use canActivate to fetch data and store the data in the service. Below is the code snippet for the same

@Injectable()
export class FetchUserData implements CanActivate {
  constructor(
    private userService: UserService,
    private httpClient: HttpClient
  ) {}
  public modalRef: BsModalRef;
  canActivate() {
    return this.httpClient
      .get("some/api/route")
      .map(e => {
        if (e) {
          this.userService.setUserDetails(e);
          return true;
        }
        return true;
      })
      .catch(() => {
        return Observable.of(false);
      });
  }
}

It worked for me well. You will have no problem in refreshing the child route.

Renil Babu
  • 2,118
  • 1
  • 20
  • 29
  • Seems to be working solution, but still I would request angular team to fix this issue: https://github.com/angular/angular/issues/24187 – ekar May 02 '20 at 23:08
  • My solution was to use resolvers instead of guards. Then the syncronous order and hierarchy will be kept. – ekar May 03 '20 at 09:31
0

My solution to this situation was to wrap the entire application in a lazy module and hang canLoad on it

{
    path: '',
    children: [
      {
        path: '',
        canLoad: [PortalResolver],
        loadChildren: () => import('./portal/portal.module').then(m => m.PortalModule),
      }
    ],
  },
0

Usage notes When both guard and resolvers are specified, the resolvers are not executed until all guards have run and succeeded. For example, consider the following route configuration:

{
 path: 'base'
 canActivate: [BaseGuard],
 resolve: {data: BaseDataResolver}
 children: [
  {
    path: 'child',
    guards: [ChildGuard],
    component: ChildComponent,
    resolve: {childData: ChildDataResolver}
   }
 ]
}

The order of execution is: BaseGuard, ChildGuard, BaseDataResolver, ChildDataResolver.

https://angular.io/api/router/Resolve#usage-notes