mirror of
https://github.com/angular/angular
synced 2026-05-24 09:28:37 +00:00
To increase the ease of development we are moving @angular/docs into the adev directory within this repo. While we are doing this to improve our development experience in the short term, efforts are also in place to maintain a division between this @angular/docs (shared) code and adev itself, so that it can be extracted back out in the future when components is ready to leverage it as well. PR Close #57132
92 lines
2.4 KiB
TypeScript
92 lines
2.4 KiB
TypeScript
/*!
|
|
* @license
|
|
* Copyright Google LLC All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by an MIT-style license that can be
|
|
* found in the LICENSE file at https://angular.dev/license
|
|
*/
|
|
|
|
import {
|
|
DestroyRef,
|
|
ENVIRONMENT_INITIALIZER,
|
|
EnvironmentInjector,
|
|
Injectable,
|
|
Injector,
|
|
Provider,
|
|
ProviderToken,
|
|
Type,
|
|
createEnvironmentInjector,
|
|
inject,
|
|
} from '@angular/core';
|
|
|
|
/**
|
|
* Convience method for lazy loading an injection token.
|
|
*/
|
|
export async function injectAsync<T>(
|
|
injector: Injector,
|
|
providerLoader: () => Promise<ProviderToken<T>>,
|
|
): Promise<T> {
|
|
const injectImpl = injector.get(InjectAsyncImpl);
|
|
return injectImpl.get(injector, providerLoader);
|
|
}
|
|
|
|
@Injectable({providedIn: 'root'})
|
|
class InjectAsyncImpl<T> {
|
|
private overrides = new WeakMap(); // no need to cleanup
|
|
override<T>(type: Type<T>, mock: Type<unknown>) {
|
|
this.overrides.set(type, mock);
|
|
}
|
|
|
|
async get(injector: Injector, providerLoader: () => Promise<ProviderToken<T>>): Promise<T> {
|
|
const type = await providerLoader();
|
|
|
|
// Check if we have overrides, O(1), low overhead
|
|
if (this.overrides.has(type)) {
|
|
const override = this.overrides.get(type);
|
|
return new override();
|
|
}
|
|
|
|
if (!(injector instanceof EnvironmentInjector)) {
|
|
// this is the DestroyRef of the component
|
|
const destroyRef = injector.get(DestroyRef);
|
|
|
|
// This is the parent injector of the injector we're creating
|
|
const environmentInjector = injector.get(EnvironmentInjector);
|
|
|
|
// Creating an environment injector to destroy it afterwards
|
|
const newInjector = createEnvironmentInjector([type as Provider], environmentInjector);
|
|
|
|
// Destroy the injector to trigger DestroyRef.onDestroy on our service
|
|
destroyRef.onDestroy(() => {
|
|
newInjector.destroy();
|
|
});
|
|
|
|
// We want to create the new instance of our service with our new injector
|
|
injector = newInjector;
|
|
}
|
|
|
|
return injector.get(type)!;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Helper function to mock the lazy loaded module in `injectAsync`
|
|
*
|
|
* @usage
|
|
* TestBed.configureTestingModule({
|
|
* providers: [
|
|
* mockAsyncProvider(SandboxService, fakeSandboxService)
|
|
* ]
|
|
* });
|
|
*/
|
|
export function mockAsyncProvider<T>(type: Type<T>, mock: Type<unknown>) {
|
|
return [
|
|
{
|
|
provide: ENVIRONMENT_INITIALIZER,
|
|
multi: true,
|
|
useValue: () => {
|
|
inject(InjectAsyncImpl).override(type, mock);
|
|
},
|
|
},
|
|
];
|
|
}
|