Repository navigation
Description
I'm submitting a ... (check one with "x")
[x] bug report => search github for a similar issue or PR before submitting
[ ] feature request
[ ] support request => Please do not submit support request here, instead see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question
Current behavior
I create 3 services:
@Injectable()
export class Dog {
constructor() {
console.log("Dog constructor");
}
}
@Injectable()
export class Child {
constructor(injector: Injector) {
let dog = injector.get(Dog);
console.log("Child constructor | injector: %o | dog: %o", injector, dog);
}
}
@Injectable()
export class Parent {
constructor(child: Child,
dog: Dog) {
console.log("Parent constructor | child: %o | dog: %o", child, dog);
}
}Now I create the APP_INITIALIZER factory:
export function configFactory(
parent: Parent) {
return () => {
console.log(parent);
}
}
export const config: any = {
provide: APP_INITIALIZER,
deps: [Parent],
useFactory: configFactory,
multi: true
};Finally I add everything to the module
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
FormsModule,
HttpModule
],
providers: [
Parent,
Child,
Dog,
config
],
bootstrap: [AppComponent]
})
export class AppModule { }After I run It I get the following console messages:
Child constructor | injector: AppModuleInjector | dog: undefined
Dog constructor
Parent constructor | child: Child | dog: Dog
It looks like a Child constructor tries to inject a Dog, which is also queued to inject in a Parent constructor, but at that time somehow can't create a Dog, thus returning undefined.
Expected behavior
The console should return:
Dog constructor
Child constructor | injector: AppModuleInjector | dog: Dog
Parent constructor | child: Child | dog: Dog
There are several ways to fix that:
- Change the parameter order in a Parent constructor, so that Dog is injected before Child:
@Injectable()
export class Parent {
constructor(dog: Dog,
child: Child) {
console.log("Parent constructor | child: %o | dog: %o", child, dog);
}
}- Inject Dog in a Child constructor instead of using Injector:
@Injectable()
export class Child {
constructor(dog: Dog) {
console.log("Child constructor | dog: %o", dog);
}
}- Injecting Parent in a Component instead of APP_INITIALIZER
Minimal reproduction of the problem with instructions
http://plnkr.co/edit/OhqJKLD8zuZOVn9RF0UJ
What is the motivation / use case for changing the behavior?
Please tell us about your environment:
Windows 7 Enterprise, Webstorm 2016.3.3
- Angular version: 2.0.X
Angular 2.4.7
@angular-cli 1.0.0-beta.30
- Browser: [all | Chrome XX | Firefox XX | IE XX | Safari XX | Mobile Chrome XX | Android X.X Web Browser | iOS XX Safari | iOS XX UIWebView | iOS XX WKWebView ]
all
-
Language: [all | TypeScript X.X | ES6/7 | ES5]
TypeScript 2.0.10 -
Node (for AoT issues):
node --version=
Activity
JoniJnm commentedon Feb 15, 2017
I think it's not a bug.
You should use the second fix.
Injector might not be completely ready while you are injecting providers:
What angular does:
So, you have to tell angular that Child needs Dog and angular will wait for it.
Other way to fix it:
Dog will be injected in injector so will be ready later.
m-sawicki-tt commentedon Feb 15, 2017
@JoniJnm Ok, but why the app behaves "normally" when I remove a
Dogdependency from aParentclass?Take a look at this (unchanged):
A
Childis first and wants to inject aDog, then theInjectorinside aChildconstructor somehow doesn't create a newDoginstance.And now this (removed a
Dogparameter)Now a
Childis again first in aParentconstructor, but this time theInjectorproperly injects aDoginstance.JoniJnm commentedon Feb 16, 2017
Maybe because angular "creates" the objects that are not needed in APP_INITIALIZER first.
With
Parent: constructor(child: Child) {the code generated by angular is:With
Parent: constructor(child: Child, dog: Dog) {the code is:So, if you do not tell to angular the real dependencies, angular can not create a real graph and some of them might not be ready.
With
Child: constructor(dog: Dog) {the code is:Be careful using Injector, and more in APP_INITIALIZER step. It should be used only if you don't have other way.
I don't know if angular can change some logic and reference the objects first. But I think that you are doing it wrong.
At least you should include the real dependences in configFactory with
deps: [Dog, Parent],trotyl commentedon Feb 20, 2018
Has been fixed by #19558, you can try have another look at the plunker:
angular-automatic-lock-bot commentedon Sep 14, 2019
This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.
Read more about our automatic conversation locking policy.
This action has been performed automatically by a bot.