-
Notifications
You must be signed in to change notification settings - Fork 27.1k
Description
I'm submitting a...
[ ] Regression (a behavior that used to work and stopped working in a new release)
[ ] Bug report
[ X] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question
Current behavior
Angular doesn't seem to support providers which asynchronously create their object / service. For those who want to load config from a server dynamically, they seem to be encouraged to use a kludge comprised of creating a ConfigService and then using APP_INITIALIZER to delay the bootstrapping just long enough to make an async call and inject the results into the ConfigService. But, this is a hack, and is buggy with race conditions - the ConfigService may potentially be injected into other services, and be used / read from before this bootstrapping happens, causing bugs because the object gets used before it's ready.
Here's a plunk which demonstrates the problem: https://plnkr.co/edit/plWAT5i5BFtjastSdaVy?p=preview
Notice the problem is that another service will read from the ConfigService before it's truly finished being "constructed" IMO, since we need to construct the object, and then finish initializing it's state the APP_INITIALIZER step. I think reading config in a constructor is pretty common programming practice.
Expected behavior
I think it would be great to be able to do something like:
export function asyncConfigServiceFactory(api: ApiService) {
return new Promise((resolve, reject) => {
api.get('my-config.json').then(response => {
resolve(new ConfigService(response));
});
});
}
@NgModule({
providers: [
ApiService,
{
provide: ConfigService,
useAsyncFactory: asyncConfigServiceFactory,
deps: [ApiService]
},
],
})
(notice the useAsyncFactory idea to tell ng that it should wait on the promise, and use the value it produces as the service)
I think that's a pretty straight forward way to do it, but whatever you think is the best way to address it.
What is the motivation / use case for changing the behavior?
My use case is to fetch config from a server, and stick it into a service, and then inject this ConfigService into other services. I do not want to inject ConfigService into other stuff until it's fully constructed and ready to be used - in other words, until the asynchronous request to the server has completed and my ConfigService has all the values populated into it.
I've seen quite a few other users trying to accomplish the same thing on Stackoverflow. This kludge is becoming the defacto way to do it, and SO answers are getting highly upvoted, and multiple articles are being published on other websites - all recommending a bug-prone method. That's not good for the framework's reputation long term. It should be easy to do it "the right way", whatever that is.
Environment
Angular version: 5.1
Others:
Other issues that would be well served by async providers:
#19448
#20383