启动时从API数据进行Angular 5构建路由 [英] Angular 5 Build routes from API data at startup
问题描述
我需要基于从API(站点地图)接收到的数据在Angular应用程序启动时创建路由. 1. APP_INITIALIZER调用SettingsService.loadSettings从API获取数据 2.数据到达路由并建立所需的路由.
I need to create routes at Angular application startup based on the data received from API (site map). 1. APP_INITIALIZER calls SettingsService.loadSettings to get the data from API 2. Data comes to ROUTES and desired routes are built.
app.module.ts
app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule, APP_INITIALIZER } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';
import { RouterModule, ROUTES } from '@angular/router';
import { AppComponent } from './app.component';
import { MuseumComponent } from './museum/museum.component';
import { SettingsService } from './services/settings.service';
export function initSettings(settings: SettingsService) {
return () => settings.loadSettings();
}
export function buildRoutes(settings: SettingsService) {
console.log('SettingsService.currentSettings', settings.currentSettings);
const routes = [];
settings.currentSettings.site_map.forEach(element => {
routes.push({
path: `/${element.url}`,
component: MuseumComponent
});
});
routes.push({
path: '**',
component: AppComponent
});
console.log(routes);
return routes;
}
@NgModule({
declarations: [
AppComponent,
MuseumComponent
],
imports: [
BrowserModule,
HttpClientModule,
RouterModule.forRoot([])
],
providers: [
SettingsService,
{
'provide': APP_INITIALIZER,
'useFactory': initSettings,
'deps': [SettingsService],
'multi': true
},
{
'provide': ROUTES,
'multi': true,
'useFactory': buildRoutes,
'deps': [SettingsService]},
],
bootstrap: [AppComponent]
})
export class AppModule { }
settings.service.ts
settings.service.ts
import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Config } from './../config';
@Injectable()
export class SettingsService {
private apiUrl = Config.apiUrl;
public currentSettings;
constructor(
private http: HttpClient
) { }
loadSettings(): Promise<any> {
return new Promise ((resolve, reject) => {
const url = this.apiUrl + `/settings`;
this.http.get(url)
.subscribe(
response => {
console.log('API answer: ', response);
this.currentSettings = response;
resolve(true);
},
err => {
console.log('Server error: ' + JSON.stringify(err));
reject(false);
}
);
});
}
}
我在控制台上收到错误消息:
I receive an error on console:
SettingsService.currentSettings undefined
main.ts:12 TypeError: Cannot read property 'site_map' of undefined
如果我这样做:
app.module.ts
app.module.ts
export function buildRoutes(settings: SettingsService) {
console.log('SettingsService.currentSettings', settings.currentSettings);
const routes = [];
/*settings.currentSettings.site_map.forEach(element => {
routes.push({
path: `/${element.url}`,
component: MuseumComponent
});
});*/
routes.push({
path: '**',
component: AppComponent
});
console.log(routes);
return routes;
}
我收到:
SettingsService.currentSettings undefined
app.module.ts:27 [{…}]
0: {path: "**", component: ƒ} length: 1 __proto__: Array(0)
settings.service.ts:23 API answer: {languages: Array(2), entity_types:
Array(5), site_map: Array(2)}
core.js:3688 Angular is running in the development mode. Call
enableProdMode() to enable the production mode.
看起来,ROUTES发生在APP_INITIALIZER之前.为什么呢?
Look's like, ROUTES is happened before APP_INITIALIZER. Why it is?
推荐答案
I used wrong approach, solution was founded here Angular. Router DI not working when using APP_INITIALIZER
正确的代码:
app.module.ts
app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule, APP_INITIALIZER } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';
import { RouterModule } from '@angular/router';
import { AppComponent } from './app.component';
import { MuseumComponent } from './museum/museum.component';
import { SettingsService } from './services/settings.service';
import { ApiService } from './services/api.service';
export function initSettings(settings: SettingsService) {
return () => settings.loadSettings();
}
@NgModule({
declarations: [
AppComponent,
MuseumComponent
],
imports: [
BrowserModule,
HttpClientModule,
RouterModule.forRoot([])
],
entryComponents: [
MuseumComponent
],
providers: [
SettingsService,
ApiService,
{
'provide': APP_INITIALIZER,
'useFactory': initSettings,
'deps': [SettingsService],
'multi': true,
}
],
bootstrap: [AppComponent]
})
export class AppModule { }
settings.service.ts
settings.service.ts
import { Injectable, Injector } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Router } from '@angular/router';
import { ApiService } from './api.service';
import { MuseumComponent } from '../museum/museum.component';
@Injectable()
export class SettingsService {
currentSettings: any;
constructor(
private injector: Injector,
private api: ApiService
) { }
loadSettings(): Promise<any> {
return new Promise((resolve, reject) => {
setTimeout(() => {
const router = this.injector.get(Router);
console.log(router);
this.api.getSettings()
.subscribe(
response => {
this.currentSettings = response;
this.currentSettings.site_map.forEach(element => {
router.config.push({ path: `${element.url}`, component: MuseumComponent });
});
resolve(true);
},
err => {
console.log(err);
reject(false);
}
);
});
});
}
}
api.service.ts
api.service.ts
import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import { Config } from './../config';
@Injectable()
export class ApiService {
private apiUrl = Config.apiUrl;
constructor(
private http: HttpClient
) { }
public getSettings(): Observable<any> {
const url = this.apiUrl + `/settings`;
return this.http.get(url);
}
}
这篇关于启动时从API数据进行Angular 5构建路由的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!