Search code examples
angulartypescriptangular2-routing

Angular lazy load with parent route parameter


I have a ProfileModule with the following routing :

// profile-routing.module

const routes: Routes = [
  {
    path: ':id',
    component: ProfilePageComponent,
    children: [
      {
        path: '',
        redirectTo: 'feed',
        pathMatch: 'full'
      },
      {
        path: 'feed',
        component: NewsFeedComponent
      },
      {
        path: 'gallery',
        component: MediasGalleryComponent
      }
    ]
  }
];

It works as follow:

  1. ProfilePageComponent fetches the profile ID in routing parameters and sends it to a ProfilePageService
  2. NewsFeedComponent and MediasGalleryComponent receive the profile ID from ProfilePageService

Now, these two pages have been moved into two separate modules (respectively NewsModule and MediasModule), that I want to be lazy loaded in this routing. I cannot use ProfilePageService anymore. I came up with this solution :

// profile-routing.module

const routes: Routes = [
  {
    path: ':id',
    component: ProfilePageComponent,
    children: [
      {
        path: '',
        redirectTo: 'news/:id/feed', // same as the parent ID
        pathMatch: 'full'
      },
      {
        path: 'news',
        loadChildren: () => import('./news/news.module').then(m => m.NewsModule)
      },
      {
        path: 'medias',
        loadChildren: () => import('./medias/medias.module').then(m => m.MediasModule)
      }
    ]
  }
];

// news-routing.module

const routes: Routes = [{
  path: ':profileId/feed',
  component: NewsFeedComponent
}];

// medias-routing.module

const routes: Routes = [{
  path: ':profileId/gallery',
  component: MediasGalleryComponent
}];

This solution is not working, since I cannot get the profile ID parameter from parent route. How can I avoid this problem ?

Moreover, I don't like the fact that profile ID is duplicated in the URL. What would be the Angular way to do things ?


Solution

  • This is because the child modules just see the path to their module as their root path, which does not include the :id. You can have a sharedService that is provided in your application root and reads the id on route changes. Then you can read that ID from within the child module.

    @Injectable()
    export class RouterStateService {
      params$: Observable<Params>;
    }
    

    In your app component you can then do

    @Component(...)
    export class AppComponent {
      constructor(private activatedRoute: ActivatedRoute, private routerState: RouterStateService) {}
    
      ngOnInit() {
        this.routerState.params$ = this.activatedRoute.params;
      }
    }
    

    And in your child-component/module you can use it as

    @Component(...)
    export class WhatEverComponent {
      constructor(private routerState: RouterStateService) {}
    
      ngOnInit() {
        this.routerState.params$.subscribe(console.log);
      }
    }
    

    As always: Please do not forget to unsubscribe if you don't need the stream anymore.