Reputation: 125
I am new to Angular and currently using Angular6 for development purpose. Here is my query. Before my app starts I need to call three services that provide me some configs for the app. Lets call the services as Initialization, Conifg and UserDetails. So I have added the services in the app-module.ts file as below.
`
export function init_app(initService: InitializationService) {
return () => initService.getInit();
}
export function get_settings(configService: ConfigService) {
return () => configService.getConfig();
}
export function get_user_settings(userDetails: UserDetailsService) {
return () => userDetails.getSettings();
}
@NgModule({
imports: [/*my-imports*/],
providers: [
AppLoadService,
{ provide: APP_INITIALIZER, useFactory: init_app, deps: [InitializationService], multi: true },
{ provide: APP_INITIALIZER, useFactory: get_settings, deps: [ConfigService], multi: true },
{ provide: APP_INITIALIZER, useFactory: get_user_settings, deps: [UserDetailsService], multi: true }
]
})
` Now InitializationService has some values that are needed by the other two services to work properly. In app_init the services request are sent immediately.
I need my ConfigService and UserDetailsService to be called only when the call for InitializationService is done.
To tackle this I have done following,
// AppConfig.ts
export class AppConfig {
public static Config= {};
public static $subject = new Subject();
}
// InitializationService
getInit () {
const promise = new Promise((resolve, reject) => {
this.http.get().then(val => {
AppConfig.config = val;
AppConfig.$subject.next(val);
});
};
return promise;
}
//ConfigService
getConfig () {
if(AppConfig.Config.baseUrl === undefined) {
AppConfig.$subject.subscribe(val => {
this.http.get(AppConfig.Config.baseUrl).then(//doSomething);
})
}
}
So i create a static subject and subscribe to it. Once the Init service is done, it sends the next value for the subject, which is now subscribed and listened by Config service. Once the subscribe call is received I do my further operation.
Same code is repeated by my UserDetails getSettings() call.
Is my approach correct? Is there any other pattern tried and tested.
Any suggestion or better way to tackle the above?
Thanks in advance.
Regards, hawx
Upvotes: 2
Views: 1865
Reputation: 24561
Use one initialiser and control the whole flow there:
export function initAll(initService: InitializationService, configService: ConfigService, userDetails: UserDetailsService) {
return () => {
return initService.getInit().pipe(
switchMap(() => {
return flatMap([ConfigService.getConfig(), userDetails.getSettings()]);
}),
);
}
}
Please note that flatMap
assumes both operations to be completed; however this is just the approach to go. You have full control to the process over rxjs operators. And, you have only one APP_INITIALIZER
Upvotes: 2
Reputation: 125
//app-module code
export function initAll(appInitService:AppInitService, configService:ConfigService) {
// return a promise because thats what the app_init token expects. there is an open ticket with angular related to this. https://github.com/angular/angular/issues/15088
return () => {
const promise = new Promise((resolve, reject) => {
appInitService.load().then(() => {
configService.fetch().then(() => {
resolve();
});
});
});
return promise;
}
}
//appInitService.load() call
const promise = this.http.get<any>(`myConfigURL`).toPromise();
promise.then(response => {
Object.assign(AppConfig.ENV, response.value.parameters);
});
return promise;
// config service call
const promise = this.http.get<any>(myConfigUrl).toPromise();
promise.then(response => {
//do something with response
});
return promise;
I took this approach because it solves my problem of having and maintaining Subject. Plus I was short on time to try and debug of what was going wrong with the Observable stuff.
Thanks for the response though.
Upvotes: 0