问题
In Angular 2.0 stable, I have a application in which I have to define/config routes based on JSON data I receive. I don't have any predefined routes.I am getting this data in the constructor of my bootstrap component.
How can i achieve that? Is it possible?
回答1:
The way that I achieved this was to load the routes before bootstrapping the angular app. This way when the app starts all the dynamic routes are already there.
So you have to load all the routes in the main.ts file before the platformBrowserDynamic().bootstrapModule(AppModule);
line.
Here is an example of the main.ts file where the routes are fetched as a json and loaded before bootstrapping.
import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { environment } from './environments/environment';
import { AppModule } from './app/app.module';
import { IRoute, IRouteData } from './core/models/route';
import { getComponent } from './core/utils/type-component-mapper';
import { AppRoutes } from './app/app.routes';
export function main() {
console.log('[main]')
return platformBrowserDynamic()
.bootstrapModule(AppModule)
.catch(err => console.error(err));
}
switch (document.readyState) {
case 'interactive':
case 'complete':
getRoutes();
break;
case 'loading':
default:
document.addEventListener('DOMContentLoaded', () => getRoutes());
}
function getRoutes() {
// This is where you load the routes json from your api
fetch(environment.apiUrl + '/api/routes/get').then((value: Response) =>
{
return value.json();
}).then((routes: IRoute[]) => {
routes.forEach((o: IRoute) => {
iterate(o);
});
// add each dynamic route to the angular route collection
AppRoutes.unshift(routes[0]);
// all dynamic routes have been added, start the angular app
main();
});
}
function iterate(route: IRoute) {
var children = route.children;
if (children) {
Array.from(children).forEach((o: IRoute) => {
iterate(o)
});
}
var component = getComponent(route.data.type);
if (component) {
route.component = component;
}
}
In this example the routes json which is returned from the api would be in this form:
[{
"path" : Shop,
"data" : {
"type" : ShopPage
},
"children" : [{
"path" : Bread,
"data" : {
"type" : ProductPage
}
},
{
"path" : Milk,
"data" : {
"type" : ProductPage
}
}]
}]
This Json data is parsed into the IRoute and IRouteData types:
export interface IRoute {
path: string;
data: IRouteData;
children?: IRoute[];
}
export interface IRouteData {
type: string;
}
It is also important that you export your AppRoutes const, so that you can push the new dynamic routes to your AppRoutes collection. It would look something like this:
export const AppRoutes: Routes = [
{
path: 'hardCodedWelcome',
component: WelcomeComponent
}
];
You also need to add the correct component for each route. In this case, I do a switch on the data type property to get the correct component. This is why I import the get component function from the type-component-mapper file which looks like this:
import { Router, Route } from '@angular/router';
import { Type } from '@angular/core';
import { PageTypes } from './page-types';
import { ShopComponent } from '../../app/Shop/shop.component';
import { ProductComponent } from '../../app/Product/Product.component';
export function getComponent(type: string): Type<any> {
switch (type) {
case PageTypes.Shop: {
return ShopComponent;
}
case PageTypes.Product: {
return ProductComponent;
}
}
}
Page types here is just a simple list of page types so I do not have to use magic strings.
export const PageTypes = {
Shop: 'ShopPage',
Product: 'ProductPage',
};
When the app starts all dynamic routes are there in the route collection and can be resolved as normal by angular. This adds some startup time to the app, depending on how many routes there are. But once the app has started, all routes are in the config routes collection and there is no further impact on performance.
Note this works only if AOT is false.
If you want to use this with AOT, you have to inject the router into the app.component constructor and then add this line:
router.resetConfig(allRoutes);
where all routes is the array you pushed the routes to before bootstrapping.
回答2:
It is possible using APP_INITIALIZER, function which is executed when an application is initialized.
There is a great article about fetching routes from an API when the app is initialized https://long2know.com/2017/11/angular-dynamic-routes-and-application-initialization/
Basically, you have to create a service which fetches the data (routes) from the API, create a factory in AppModule and add it to providers array. The article I've mentioned above describes it very clearly.
来源:https://stackoverflow.com/questions/40040275/angular-2-dynamic-routing-from-json-data