Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 7 Routes with Resolvers don't load Components

I'm having an Angular 7 issue where a module's child components that have a resolver on the route don't load.

app-routing.module.ts

{
  path: 'Account',
  loadChildren: './account/account.module#AccountModule'
}

account-routing.module.ts

{
  path: 'Profile',
  component: ProfileComponent,
  resolve: {
    profile: ProfileResolver
  }
}

profile.resolver.ts

@Injectable()
export class ProfileResolver implements Resolve<Profile> {

  constructor(private readonly accountService: AccountService) {
  }

  resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Profile> {
    return this.accountService.profile();
  }
}

profile.component.ts

@Component({
⋮
})
export class ProfileComponent implements OnInit {

  model: Profile;

  constructor(private readonly route: ActivatedRoute) {
  }

  ngOnInit(): void {
    this.model = this.route.snapshot.data['profile'] as Profile;
  }
}

account.service.ts

@Injectable()
export class AccountService {

  constructor(protected readonly http: HttpClient) {
  }

  profile(): Observable<Profile> {
    return this.http.get<Profile>(`${environment.apiUrl}/Account/Profile`);
  }
}

The behavior is that, when navigating to /Account/Profile, the ProfileResolver is called, hits the server, and gets a 200 response with the Profile object (I can see it in the Network tab), and then... nothing. Neither the constructor or the ngOnInit method of ProfileComponent are called.

If I remove the ProfileResolver from the AccountRoutingModule and call the AccountService directly from the ngOnInit method, it works. But there are a number of template parse errors from the template while it waits for the response (which is the whole reason I want to use the resolve).

Is there something extra I need to do to make a resolver work with these modules?

This might also be the same issue as described here: Angular Router don't load component with resolver

UPDATE: I turned on enableTracing so I could see what is happening. Here is the output:

Router Event: NavigationStart
NavigationStart(id: 2, url: '/Account/Profile')
NavigationStart {id: 2, url: "/Account/Profile", navigationTrigger: "imperative", restoredState: null}

Router Event: RoutesRecognized
RoutesRecognized(id: 2, url: '/Account/Profile', urlAfterRedirects: '/Account/Profile', state: Route(url:'', path:'') { Route(url:'Account', path:'Account') { Route(url:'Profile', path:'Profile') }  } )
RoutesRecognized {id: 2, url: "/Account/Profile", urlAfterRedirects: "/Account/Profile", state: RouterStateSnapshot}

Router Event: GuardsCheckStart
GuardsCheckStart(id: 2, url: '/Account/Profile', urlAfterRedirects: '/Account/Profile', state: Route(url:'', path:'') { Route(url:'Account', path:'Account') { Route(url:'Profile', path:'Profile') }  } )
GuardsCheckStart {id: 2, url: "/Account/Profile", urlAfterRedirects: "/Account/Profile", state: RouterStateSnapshot}

Router Event: ChildActivationStart
ChildActivationStart(path: '')
ChildActivationStart {snapshot: ActivatedRouteSnapshot}

Router Event: ActivationStart
ActivationStart(path: 'Profile')
ActivationStart {snapshot: ActivatedRouteSnapshot}

Router Event: GuardsCheckEnd
GuardsCheckEnd(id: 2, url: '/Account/Profile', urlAfterRedirects: '/Account/Profile', state: Route(url:'', path:'') { Route(url:'Account', path:'Account') { Route(url:'Profile', path:'Profile') }  } , shouldActivate: true)
GuardsCheckEnd {id: 2, url: "/Account/Profile", urlAfterRedirects: "/Account/Profile", state: RouterStateSnapshot, shouldActivate: true}

Router Event: ResolveStart
ResolveStart(id: 2, url: '/Account/Profile', urlAfterRedirects: '/Account/Profile', state: Route(url:'', path:'') { Route(url:'Account', path:'Account') { Route(url:'Profile', path:'Profile') }  } )
ResolveStart {id: 2, url: "/Account/Profile", urlAfterRedirects: "/Account/Profile", state: RouterStateSnapshot}

So it looks like the ResolveEnd event is never firing. I found this issue: Router's ActivatedRoute data returns empty {} if module is lazy. It seems like it may be related but I'm not sure how I would implement that fix here.

like image 567
crgolden Avatar asked Dec 02 '18 02:12

crgolden


People also ask

How would I restrict access to routes in Angular?

Include AuthGuard to Route Now for each request of the route, the verify() function will be called and if the verify() function returns true, then only we can access the particular route. If it returns false, we are not able to access it. This is how we can restrict the routes from unauthorized user access.

Can not match any routes Angular?

This generally occurs when there is a mismatch in the routes specified, or a component which is not present in our routing configuration, or if there is the use of multiple routes in our angular application which is not properly configured.

Should I use resolver in Angular?

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 route Guard is helpful in preventing Unauthorised access to a component?

Well, there is a difference, the canActivate exists to prevent unauthorized users from accessing a route, while canLoad is used to prevent the application from loading an entire module or component in a lazy way (lazy loading) if the user is not authorized.


1 Answers

I consulted the Routing & Navigation guide again and changed my Resolver to look like it does there:

profile.resolver.ts

@Injectable()
export class ProfileResolver implements Resolve<Profile> {

  constructor(private readonly accountService: AccountService) {
  }

  resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Profile> {
    return this.accountService.profile().pipe(
      take(1),
      map((profile: Profile) => profile));
  }
}

The key was adding the take(1). Without this, the ResolveEnd event is never fired and the Router just hangs.

like image 89
crgolden Avatar answered Sep 27 '22 20:09

crgolden