I am looking into the possibility for Angular 8 to dynamically create the routing from a REST service.
This idea is that a user can create pages which should be available for access by routing on the web page.
I have seen options to dynamically add routes, however I would like to have the routes loaded before the rest of the app, so that when a user would access: 'website/generatedPage' the routing is in place before the app is fully loaded.
How do I make sure the routes from the REST service are in place before the app continues with the routing options?
The following piece of code adds the routing to late:
constructor(
private sitemapService: SitemapService,
private router: Router
) {
this.sitemapService.getSiteMap().then(result => {
result.forEach(sitemapItem => {
this.router.config.push({ path: sitemapItem.pageName, component: PageComponent });
});
});
}
With this code you can navigate to the page when the app is aready loaded, however, when you would directly request the route, it is not loaded yet.
Thank you in advance!
Ok, so I had this exact same issue and I was actually going to use your "solution" when I stumbled up on these three articles and used a combination of them to come up with the solution.
References:
https://long2know.com/2017/11/angular-dynamic-routes-and-application-initialization/
https://medium.com/codegg/pre-loading-user-specific-routes-in-angular-ce829430e1cb
https://www.tektutorialshub.com/angular/angular-how-to-use-app-initializer/#where-to-use-app-initializer
My use case: I need to create routes based on a GET response
Here's what worked for me:
1. First, I created a new app-init
service:
import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
@Injectable()
export class AppInitService {
constructor(private Router: Router) {}
init() {
return new Promise<void>((resolve, reject) => {
// Simple example from an array. In reality, I used the response of
// a GET. Important thing is that the app will wait for this promise to resolve
const newDynamicRoutes = ['bulbasaur','charmander','squirtle']
const routes = this.Router.config;
newDynamicRoutes.forEach(routeName => {
routes.push({ path: routeName, component: <YourComponent> });
});
this.Router.resetConfig(routes);
resolve();
});
}
}
2. Then, I use it in app.module.ts
with APP_INITIALIZER
import { NgModule, APP_INITIALIZER } from '@angular/core';
import { AppInitService } from './services/app-init/app-init.service'; // New service that I created
...
export function initializeApp(appInitService: AppInitService) {
return (): Promise<any> => {
return appInitService.init();
}
}
...
providers: [
AppInitService,
{
provide: APP_INITIALIZER,
useFactory: initializeApp,
multi: true,
deps: [AppInitService]
}
],
bootstrap: [AppComponent]
})
export class AppModule {}
This works like a charm. It lets me create routes based on the response from an API.
I have found a solution, however it is more of a workaround. For my situation it works, but still if anyone has a cleaner solution it will be mutch appreciated.
In the appModule I have defined routes for all predefined routes.
I have a website module where all pages created by the user will be initialized.
So the workaround:
In the app-routing I send all non defined routes to the website module:
{ path: '**', loadChildren: () => import('./website/website.module').then(module => module.WebsiteModule) }
In the website module I forward all calls to a PageComponent
path: '**', component: PageComponent
In the page component I request the page from the rest service, if it is a 404 I redirect to the predefined PageNotFound.
As I said, it is definitely not clean but it works. So any clean solutions which let me create a RoutingConfig which is fully defined from rest would be much appreciated.