Angular 5 Build routes from API data at startup

与世无争的帅哥 提交于 2019-12-11 03:22:28

问题


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

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

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

If I make this:

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;
}

I receive:

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.

Look's like, ROUTES is happened before APP_INITIALIZER. Why it is?


回答1:


I used wrong approach, solution was founded here Angular. Router DI not working when using APP_INITIALIZER

Right code:

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

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

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);
 }
}


来源:https://stackoverflow.com/questions/49953281/angular-5-build-routes-from-api-data-at-startup

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!