Dependency Injection: Advanced strategies
Edit on GitHubThis document describes advanced strategies of using dependency injection (DI).
The INJECTOR token
In some cases, dependencies may be optional or resolved at runtime, making it difficult to inject them directly into a service. In such cases, you can inject the current DI container using the INJECTOR
token. Example:
constructor(protected injector = inject(INJECTOR)) {}
With the INJECTOR
token injected, you can use the INJECTOR
’s inject
method to dynamically resolve dependencies at runtime. Example:
someServiceMethod(field) {
const template = this.injector.inject(`${FormFieldRenderer}-${field.type}`);
}
In this example, the inject
method is used to resolve a dependency based on a dynamic token that includes the field
type. Because the field
type is only known at runtime, it’s impossible to inject the dependency directly. Instead, the INJECTOR
token is injected, allowing the inject
method to resolve the dependency dynamically.
Multi-providers
Most dependencies in an application correspond to only one value, like a class. In some cases, it is useful to have dependencies with multiple values, like HTTP interceptors or normalizers. However, it’s not very practical to configure these dependencies separately, because the application needs to access them all together at once. Therefore, you can use a special type of dependency that accepts multiple values and is linked to the same dependency injection token. These are called multi-providers.
There are different types of multi-providers based on location an number of asterisks(*
) in the name of their tokens. They are described in the following sections.
Providers with an asterisk in the end of token name
These providers define multi-providers with an array of elements. The name of their token looks like [token-base-name]*
.
[
{ provider: 'multi*', useValue: 'a' },
{ provider: 'multi*', useValue: 'b' },
{ provider: 'multi*', useValue: 'c' },
];
///
inject('multi*'); // [a,b,c];
Providers with an asterisk in the middle of token name
Based on token name, these providers define the following:
[token-base-name]*[token-specifier-name]
: a single provider.[token-base-name]*
: multi-providers with an array of elements.
[
{ provider: 'multi*a', useValue: 'a' },
{ provider: 'multi*b', useValue: 'b' },
{ provider: 'multi*c', useValue: 'c' },
];
///
inject('multi*a'); // a;
inject('multi*'); // [a,b,c];
Providers with two and more asterisks in token name
Based on token name, these providers define the following:
[token-base-name]*[sub-token-name]*[token-specifier-name]
: a single provider.[token-base-name]*
: multi-providers with an array of elements.[token-base-name]*[sub-token-name]*
: multi-providers with an array of elements.
[
{ provider: 'multi*a', useValue: 'a' },
{ provider: 'multi*b', useValue: 'b' },
{ provider: 'multi*new*c', useValue: 'c' },
{ provider: 'multi*new*d', useValue: 'd' },
];
///
inject('multi*a'); // a;
inject('multi*new*c'); // c;
inject('multi*'); // [a,b,c,d];
inject('multi*new*'); // [c,d];
You can also combine multiple providers by defining a provider with the [token-base-name]*[token-specifier-name]
token and adding another one with the [token-base-name]*
token.
[
{ provider: 'multi*a', useValue: 'a' },
{ provider: 'multi*', useValue: 'b' },
];
///
inject('multi*a'); // a;
inject('multi*'); // [a,b];
In summary, providers with different asterisk patterns in their token names offer various ways to define single and multi-providers. These patterns allow for more flexibility and organization when managing dependencies in an application.
Thank you!
For submitting the form