Good day to all.

Please help me solve the following problem: I have an application configuration file - app.config.json. It has some useful information. There is also an interface that respects the structure of this file. In addition, there is a service that loads data from a file into a static object of the interface. However, when the application starts, it seems that the download did not happen.

app.config.json

{ "appUrl": "http://localhost:8080/asterisk-prime", "routes": { "device": "device", "extension": "extension", "queue": "queue", "queueMember": "queueMember" }, "apiEndpoints": { "device": "/api/device", "extension": "/api/extension", "queue": "/api/queue", "queueMember": "/api/queueMember" }, "stompEndpoint": "/socket" } 

iapp.config.ts

 export interface IAppConfig { appUrl: string; routes: { device: string, extension: string, queue: string, queueMember: string }; apiEndpoints: { device: string, extension: string, queue: string, queueMember: string }; stompEndpoint: string; } 

app.config.service.ts

 @Injectable({ providedIn: 'root' }) export class AppConfigService { static settings: IAppConfig; constructor(private httpClient: HttpClient) { } loadConfig() { const configFile = 'src/assets/config/app.config.json'; return new Promise<void>((resolve, reject) => { this.httpClient.get<IAppConfig>(configFile) .toPromise() .then(response => { AppConfigService.settings = response; LoggerService.log('Config was loaded'); resolve(); }) .catch(err => { LoggerService.error('Error while loading config.', err); reject(`Could not load file '${configFile}': ${JSON.stringify(err)}`); }); }); } } 

app.module.ts

 ... export function loadConfig(appConfigService: AppConfigService) { return () => appConfigService.loadConfig(); } ... providers: [ AppConfigService, { provide: APP_INITIALIZER, useFactory: loadConfig, deps: [AppConfigService], multi: true } ], ... 

Actually, the error occurs in the routing module during the initialization of routes.

app-routing.module.ts

 const routes: Routes = [ {path: '', redirectTo: '/', pathMatch: 'full'}, {path: '', component: HomePageComponent}, {path: 'about', component: AboutPageComponent}, {path: AppConfigService.settings.routes.device, loadChildren: './path/to/children.module#ChildrenModule'}, {path: AppConfigService.settings.routes.extension, loadChildren: './path/to/children.module#ChildrenModule'}, {path: AppConfigService.settings.routes.queue, loadChildren: './path/to/children.module#ChildrenModule'}, {path: AppConfigService.settings.routes.queueMember, loadChildren: './path/to/children.module#ChildrenModule'} 

Error in browser: Cannot read property 'routes' of undefined .

  • because loadConfig an asynchronous function, you are trying to reach the routes property at the moment when the response from src/assets/config/app.config.json has not yet arrived - overthesanity
  • after your update it is unclear what question you are asking, if you yourself answered your question, then put the updated section in response and tick - overthesanity

1 answer 1

At the moment, I decided to put everything in a separate configuration file, except for the routes. Routes left inside the application. I implement the config with routs using the declared token.

iapp.config.routes.ts

 export interface IAppConfigRoutes { routes: any; } 

app.config.routes.ts

 export let APP_CONFIG_ROUTES = new InjectionToken('app.config.routes'); export const AppConfigRoutes: IAppConfigRoutes = { routes: { device: 'device', extension: 'extension', queue: 'queue', queueMember: 'queueMember' } }; 

app.module.ts

 export function loadConfig(appConfigService: AppConfigService) { return () => appConfigService.loadConfig(); } ... providers: [ AppConfigService, { provide: APP_INITIALIZER, useFactory: loadConfig, deps: [AppConfigService], multi: true }, { provide: APP_CONFIG_ROUTES, useValue: AppConfigRoutes } ], ... 

Using AppConfigRoutes in a component (example):

header.component.ts

 export class HeaderComponent implements OnInit { private readonly appConfig: any; readonly angularLogo = require('../../../../assets/images/angular-white-transparent.svg'); menuItems: any[]; constructor(@Inject(APP_CONFIG_ROUTES) appConfig: IAppConfigRoutes) { this.appConfig = appConfig; } ngOnInit() { this.loadMenus(); } private loadMenus(): void { this.menuItems = [ {name: 'Device', link: '/' + this.appConfig.routes.device}, {name: 'Extension', link: '/' + this.appConfig.routes.extension}, {name: 'Queue', link: '/' + this.appConfig.routes.queue}, {name: 'Queue member', link: '/' + this.appConfig.routes.queueMember} ]; } } 

Use in app-routing.module.ts is essentially unchanged, only the object has changed.

 ... {path: AppConfigRoutes.routes.device, loadChildren: './path/to/children.module#ChildrenModule'}, ...