启动时从API数据进行Angular 5构建路由 [英] Angular 5 Build routes from API data at startup

查看:83
本文介绍了启动时从API数据进行Angular 5构建路由的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要基于从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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆