Search code examples
angularrxjsangular-routingcontentful

Angular: Dynamic Setting of Routes inside a Child Router Module, that is lazily-loaded


I have an application built on Angular 5 and Contentful. A service retrieves an Entry of routes from Contentful as JSON and must feed those routes to a child routing module that is lazily-loaded. Obviously, the routes would need to be dynamically set inside the child routing module, as it should be possible to update their values from Contentful at any time.

The child router module, NewsRoutingModule, looks like this:

const newsRoutes: Routes = [
  { path: '', component: NewsComponent },
  { path: '**', component: 404Component }
];

@NgModule({
  imports: [
    RouterModule.forChild(newsRoutes),
    ...
  ],
  declarations: [
    NewsComponent,
    NewsArticleComponent,
    NewsCardComponent
  ],
  ...
})

export class NewsRoutingModule {

  constructor(
    private router: Router,
    private languageService: LanguageService,
    private contentfulService: ContentfulService
  ) {
    this.loadRoutes();
  }

  loadRoutes() {

    // Language Service is used to detect the locale. Contentful Service is used to pull content from Contentful.
    this.languageService.events$.subscribe(locale => {
      this.contentfulService
        .getSearchResults('newsArticle', '', locale)
        .then(response => {

          // Content from Contentful returned as a response containing an array of Entry objects.
          response.items.forEach((entry: Entry<any>) => {
            let entryRoute = entry.fields.route;
            let hasRoute = false;

            // Check that the route doesn't already exist before adding it.
            newsRoutes.forEach((angularRoute) => {
              if (angularRoute.path == entryRoute) {
                hasRoute = true;
              }
            });
            if (!hasRoute) {
              newsRoutes.push({path: entryRoute, component: NewsArticleComponent});
            }
          });

          // Reset router's config at the end.
          this.router.resetConfig(newsRoutes);
        });
    });
  }

}

I encountered a few issues with this:

  1. If I reset the router's config, as I do at the end, the global routes are reset instead of just the routes assigned in the child routing module, NewsRoutingModule.
  2. The NewsArticleComponent that I am trying to assign for every new route from Contentful is not recognized. This is despite the fact that it is part of the declarations of @NgModule.

Solution

  • I see what you're trying to do, but there is a different process that should be applied in this situation

    Lets say you have a site with the following main routes;

    /home /home/news /home/news/article1 /home/news/article2`

    The homeand home/news would be your RouterModule.forRoot routes

    If an article route is activated, /home/news/article1, this should load your NewsArticleComponent - what you need for this is Angular Route Parameters

    { path: '/home/news/:id', component: NewsArticleComponent }
    

    In the ngOnInit of the NewsArticleComponent you can get the new article id, and retrieve the Entry from contentful. You might also want to look into Route Resolvers, where you can retrieve the data from Contentful before loading the News Component

    You will need to find example of Route Parameters, and also Route Resolvers. After that, it should be pretty straightforward

    Note: I'm not sure why you are Lazy Loading the new article component. You usually only lazy load modules that are unlikely to be used very often, but in this case it's the main component of you application