StaticInjector not working in a factory provider
See original GitHub issueBug Report
Affected Package
The issue is caused by package @angular/core. It's about DIIs this a regression?
The issue was not present while using ReflectiveInjectorDescription
Creating StaticInjector within a factory provider does not work.Using injector.create, the resulting injector can inject a class with dependencies when used in a component, but not in a factory provider. given:
@Injectable()
class TestA {
constructor() {
}
}
const testAProvider = {provide: TestA, useClass: TestA, deps: []};
@Injectable()
class TestB {
constructor(private a: TestA) {
}
}
const testBProvider = {provide: TestB, useClass: TestB, deps: [TestA]};
export function factory(injector: Injector): string {
const pi = Injector.create({providers: [testAProvider], name: 'TestA'});
const i = Injector.create({providers: [testBProvider], parent: pi, name: 'TestB'});
console.log(i.get(TestB));
return 'hi';
}
@Component({
selector: 'app-demo',
templateUrl: './component.html',
styleUrls: ['./component.scss'],
providers: [
{
provide: 'hi',
useFactory: factory,
}
]
})
causes an error shown below
but
ngOnInit(): void {
const pi = Injector.create({providers: [testAProvider], name: 'TestA'});
const i = Injector.create({providers: [testBProvider], parent: pi, name: 'TestB'});
console.log(i.get(TestB));
}
works
Minimal Reproduction
https://stackblitz.com/edit/angular-di-bug
Exception or Error
ERROR Error: Uncaught (in promise): NullInjectorError: R3InjectorError(TestB)[TestB -> TestA -> TestA -> TestA -> TestA]:
NullInjectorError: No provider for TestA!
NullInjectorError: R3InjectorError(TestB)[TestB -> TestA -> TestA -> TestA -> TestA]:
NullInjectorError: No provider for TestA!
at NullInjector.get (core.js:11081)
at R3Injector.get (core.js:11247)
at R3Injector.get (core.js:11247)
at R3Injector.get (core.js:11247)
at NgModuleRef$1.get (core.js:25341)
at R3Injector.get (core.js:11247)
at NgModuleRef$1.get (core.js:25341)
at Object.get (core.js:25055)
at lookupTokenUsingModuleInjector (core.js:3342)
at getOrCreateInjectable (core.js:3454)
at resolvePromise (zone.js:1213)
at resolvePromise (zone.js:1167)
at zone.js:1279
at ZoneDelegate.invokeTask (zone.js:406)
at Object.onInvokeTask (core.js:28661)
at ZoneDelegate.invokeTask (zone.js:405)
at Zone.runTask (zone.js:178)
at drainMicroTaskQueue (zone.js:582)
Your Environment
Angular Version:
Angular CLI: 12.0.5
Node: 14.16.0
Package Manager: npm 7.14.0
OS: darwin x64
Angular: 12.0.5
... animations, cdk, cli, common, compiler, compiler-cli, core
... forms, material, platform-browser, platform-browser-dynamic
... router
Package Version
---------------------------------------------------------
@angular-devkit/architect 0.1200.5
@angular-devkit/build-angular 12.0.5
@angular-devkit/core 12.0.5
@angular-devkit/schematics 12.0.5
@angular/flex-layout 12.0.0-beta.34
@schematics/angular 12.0.5
ng-packagr 12.0.8
rxjs 6.6.7
typescript 4.2.4
Anything else relevant?
Issue Analytics
- State:
- Created 2 years ago
- Reactions:1
- Comments:6 (3 by maintainers)
Top Results From Across the Web
Angular5: Dynamic component loading - StaticInjector error ...
I am migrating an electron application from AngularJS to Angular5 and I am facing issues in a part where I need to load...
Read more >Configuring dependency providers - Angular
The useFactory field specifies that the provider is a factory function whose implementation is heroServiceFactory . · The deps property is an array...
Read more >Dependency Injection using Decorators | by Chidume Nnamdi
Angular uses the concept of providers to configure injectors: ... Either from a class useClass or from a value useValue or from a...
Read more >angulartics/angulartics2 - Gitter
Hello, I see in the 7.2.0 release from npm registry the Launch provider is ... to use the application insights provider but there...
Read more >Providers in Angular - Scaler Topics
If the dependency is not resolved, it throws a StaticInjector error. Configuring the Angular Provider. There are different ways to configure a ...
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
I think the issue is that we end up bypassing the “active injector” in an unintended way.
What’s supposed to happen is:
R3Injector.get()
which sets that injector as active (replacing the component’s injector)injectArgs
to inject its dependencies.injectArgs
callsinject
for each dependencyinject
requests the dependency from the active injector which we set above.Unfortunately, there’s a complication here -
inject
actually allows its implementation to be replaced. Before requesting dependencies, components do this by settingdirectiveInject
as the active injection strategy. Wheninject
is called in step 3 above then, it ends up delegating todirectiveInject
, which looks up the node injector to use from the currentLView
, ignoring the injector we set in step 1.To fix this, I think
R3Injector
needs to not only set the current injector in step 1, but also clear the current injection strategy if one is set (and restore it at the end, of course, just like the active injector). That way we don’t delegate through todirectiveInject
and end up reaching the wrong injector.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.