I am wondering whether it is possible to get the angular multi-providers from (ideally) all ancestors.
Lets say that I have a INJECTION_TOKEN
X
and I have a component structure like this:
<comp-a>
<comp-b>
<comp-c></comp-c>
<comp-b>
<comp-a>
comp-a
providers:
providers: {provide: X, useValue: "A", multi: true}
comp-b
providers:
providers: {provide: X, useValue: "B", multi: true}
Is there a way how to get ["A", "B"]
in comp-c
when I use Dependency injection like:
constructor(@Inject(X) obtainedArray:TypeOfX[]) {
console.log(obtainedArray.length); //Expected to be 2
}
I have tried to use this provider in comp-b
but it is throwing a cyclic DI expection:
providers:[
{provide: X, useExisting: X, multi: true}
{provide: X, useValue: "B", multi: true}
]
As the following article states:
Angular stores providers on element by using prototypical inheritance. So, never mind whether you use multi
or not you will get the following object that contains all providers on current element:
As you can see all providers are here, but since angular just uses square brackets to get provider from element you will get only nearest provider.
To workaround this you can use addition token that uses factory to collect all parent providers:
import { Component, VERSION, InjectionToken,
Inject, SkipSelf, Optional } from '@angular/core';
@Component({
selector: 'my-app',
template: `
<comp-a>
<comp-b>
<comp-c></comp-c>
</comp-b>
</comp-a>
`
})
export class AppComponent { }
const X = new InjectionToken('X');
const XArray = new InjectionToken('XArray');
const XArrayProvider = {
provide: XArray,
useFactory: XFactory,
deps: [X, [new SkipSelf(), new Optional(), XArray]]
};
export function XFactory(x: any, arr: any[]) {
return arr ? [x, ...arr] : [x];
}
@Component({
selector: 'comp-a',
template: `<ng-content></ng-content>`,
providers: [
{ provide: X, useValue: "A" },
XArrayProvider
]
})
export class CompA { }
@Component({
selector: 'comp-b',
template: `<ng-content></ng-content>`,
providers: [
{ provide: X, useValue: "B" },
XArrayProvider
]
})
export class CompB { }
@Component({
selector: 'comp-c',
template: `{{ tokens }}`
})
export class CompC {
constructor( @Inject(XArray) public tokens: any[]) { }
}
Ng-run Example
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With