I have an angular application the imports a custom library as an npm package. I need to load the API keys dynamically from an API. Before I was loading the API keys from environment.ts file
I'm able to pass the key value to the library but the library doesn't wait for the api key value to arrive.
I've tried multiple ways to pass the value but finally was able to do it using this approach https://stackoverflow.com/a/66957293/29743045
How can I make the library wait for the api key to arrive before initializing other services that use the key value?
main.ts
fetch(`${environment.apiUrl}/keys`)
.then((response) => response.json())
.then((config) => {
platformBrowserDynamic([{ provide: STREAM_API_KEY, useValue: config.streamApiKey }])
.bootstrapModule(AppModule)
.catch((err) => console.error(err));
})
.catch((error) => {
console.error('❌ Error fetching API key:', error);
});
ChatModule
@NgModule({
imports: [
CommonModule,
HttpClientModule,
UpChatLibModule.forRoot({
apiKey: '', // Placeholder, will be set in the constructor
service: {
provide: UpChatApiIntegrationService,
useClass: ChatApiIntegrationService,
},
}),
],
providers: [],
declarations: [ChatComponent],
exports: [UpChatLibModule],
})
export class ChatModule {
constructor(@Inject(STREAM_API_KEY) private streamApiKey: string) {
UpChatLibModule.forRoot({
apiKey: this.streamApiKey,
service: {
provide: UpChatApiIntegrationService,
useClass: ChatApiIntegrationService,
},
});
}
}
UpChatLibModule
export interface UpChatConfiguration {
apiKey: string;
service: Provider;
}
@NgModule({
providers: [
StreamService,
],
declarations: [
UpChatComponent,
],
imports: [
CommonModule,
HttpClientModule,
],
exports: [
UpChatComponent,
],
})
export class UpChatLibModule {}
static forRoot(
configuration: UpChatConfiguration
): ModuleWithProviders<UpChatLibModule> {
console.log('configuration', configuration);
return {
ngModule: UpChatLibModule,
providers: [
configuration.service,
{ provide: 'CHAT_CONFIG', useValue: configuration },
],
};
}
}
Got this working finally. Thanks to @Naren Murali for helping with the solution
So as per Naren's solution from chat I'm loading the keys in the main.ts itself and then in the ChatModule I did the import with empty key. Then in the library module I used a BehaviourSUbject to hold the configuration and then subscribed it in the necessary services.
main.ts
fetch(`${environment.apiUrl}/keys`)
.then((response) => response.json())
.then((config) => {
platformBrowserDynamic([
{
provide: UpChatLibModule,
useValue: UpChatLibModule.forRoot({
apiKey: config.streamApiKey,
service: {
provide: UpChatApiIntegrationService,
useClass: ChatApiIntegrationService,
},
}),
},
])
.bootstrapModule(AppModule)
.catch((err) => console.error(err));
})
.catch((error) => {
console.error('❌ Error fetching API key:', error);
});
ChatModule
imports: [
CommonModule,
HttpClientModule,
TranslateModule,
UpChatLibModule.forRoot({
apiKey: '',
service: {
provide: UpChatApiIntegrationService,
useClass: ChatApiIntegrationService,
},
}),
],
UpChatLibModule
export class UpChatLibModule {
private static chatConfigSubject = new BehaviorSubject<UpChatConfiguration | null>(null);
static forRoot(
configuration: UpChatConfiguration
): ModuleWithProviders<UpChatLibModule> {
console.log('ApiKey', configuration);
this.chatConfigSubject.next(configuration);
return {
ngModule: UpChatLibModule,
providers: [
configuration.service,
{ provide: 'CHAT_CONFIG', useValue: this.chatConfigSubject.asObservable() },
],
};
}
}