Revert "refactor(core): remove ComponentFactoryResolver & ComponentFactory from the api surface"

This reverts commit 9d76ac8229.
g3 cleanup not complete
This commit is contained in:
Andrew Scott 2026-04-06 09:04:05 -07:00
parent 4a174b89c8
commit ecae525970
21 changed files with 364 additions and 95 deletions

View file

@ -134,6 +134,8 @@ export class ApplicationRef {
constructor();
attachView(viewRef: ViewRef): void;
bootstrap<C>(component: Type<C>, rootSelectorOrNode?: string | any): ComponentRef<C>;
// @deprecated
bootstrap<C>(componentFactory: ComponentFactory<C>, rootSelectorOrNode?: string | any): ComponentRef<C>;
readonly components: ComponentRef<any>[];
readonly componentTypes: Type<any>[];
destroy(): void;
@ -291,6 +293,31 @@ export interface ComponentDecorator {
new (obj: Component): Component;
}
// @public @deprecated
export abstract class ComponentFactory<C> {
abstract get componentType(): Type<any>;
abstract create(injector: Injector, projectableNodes?: any[][], rootSelectorOrNode?: string | any, environmentInjector?: EnvironmentInjector | NgModuleRef<any>, directives?: (Type<unknown> | DirectiveWithBindings<unknown>)[], bindings?: Binding[]): ComponentRef<C>;
abstract get inputs(): {
propName: string;
templateName: string;
transform?: (value: any) => any;
isSignal: boolean;
}[];
abstract get ngContentSelectors(): string[];
abstract get outputs(): {
propName: string;
templateName: string;
}[];
abstract get selector(): string;
}
// @public @deprecated
export abstract class ComponentFactoryResolver {
// (undocumented)
static NULL: ComponentFactoryResolver;
abstract resolveComponentFactory<T>(component: Type<T>): ComponentFactory<T>;
}
// @public
export interface ComponentMirror<C> {
get inputs(): ReadonlyArray<{
@ -2045,6 +2072,8 @@ export abstract class ViewContainerRef {
directives?: (Type<unknown> | DirectiveWithBindings<unknown>)[];
bindings?: Binding[];
}): ComponentRef<C>;
// @deprecated
abstract createComponent<C>(componentFactory: ComponentFactory<C>, index?: number, injector?: Injector, projectableNodes?: any[][], environmentInjector?: EnvironmentInjector | NgModuleRef<any>, directives?: (Type<unknown> | DirectiveWithBindings<unknown>)[], bindings?: Binding[]): ComponentRef<C>;
abstract createEmbeddedView<C>(templateRef: TemplateRef<C>, context?: C, options?: {
index?: number;
injector?: Injector;

View file

@ -10,13 +10,13 @@ import '../util/ng_hmr_mode';
import '../util/ng_jit_mode';
import '../util/ng_server_mode';
import {type Observable, Subject, type Subscription} from 'rxjs';
import {map} from 'rxjs/operators';
import {
getActiveConsumer,
setActiveConsumer,
getActiveConsumer,
setThrowInvalidWriteToSignalError,
} from '../../primitives/signals';
import {type Observable, Subject, type Subscription} from 'rxjs';
import {map} from 'rxjs/operators';
import {ZONELESS_ENABLED} from '../change_detection/scheduling/zoneless_scheduling';
import {Console} from '../console';
@ -25,8 +25,8 @@ import {Injectable} from '../di/injectable';
import {InjectionToken} from '../di/injection_token';
import {Injector} from '../di/injector';
import {EnvironmentInjector, type R3Injector} from '../di/r3_injector';
import {INTERNAL_APPLICATION_ERROR_HANDLER} from '../error_handler';
import {formatRuntimeError, RuntimeError, RuntimeErrorCode} from '../errors';
import {INTERNAL_APPLICATION_ERROR_HANDLER} from '../error_handler';
import {Type} from '../interface/type';
import {ComponentFactory, ComponentRef} from '../linker/component_factory';
import {ComponentFactoryResolver} from '../linker/component_factory_resolver';
@ -44,10 +44,10 @@ import {ViewRef as InternalViewRef} from '../render3/view_ref';
import {TESTABILITY} from '../testability/testability';
import {NgZone} from '../zone/ng_zone';
import {ProfilerEvent} from '../../primitives/devtools';
import {profiler} from '../render3/profiler';
import {isReactiveLViewConsumer} from '../render3/reactive_lview_consumer';
import {ProfilerEvent} from '../../primitives/devtools';
import {EffectScheduler} from '../render3/reactivity/root_effect_scheduler';
import {isReactiveLViewConsumer} from '../render3/reactive_lview_consumer';
import {ApplicationInitStatus} from './application_init';
import {TracingAction, TracingService, TracingSnapshot} from './tracing';
@ -441,13 +441,61 @@ export class ApplicationRef {
* While in this example, we are providing reference to a DOM node.
*
* {@example core/ts/platform/platform.ts region='domNode'}
*
* @deprecated Passing Component factories as the `Application.bootstrap` function argument is
* deprecated. Pass Component Types instead.
*/
bootstrap<C>(component: Type<C>, rootSelectorOrNode?: string | any): ComponentRef<C> {
return this.bootstrapImpl(component, rootSelectorOrNode);
bootstrap<C>(
componentFactory: ComponentFactory<C>,
rootSelectorOrNode?: string | any,
): ComponentRef<C>;
/**
* Bootstrap a component onto the element identified by its selector or, optionally, to a
* specified element.
*
* @usageNotes
* ### Bootstrap process
*
* When bootstrapping a component, Angular mounts it onto a target DOM element
* and kicks off automatic change detection. The target DOM element can be
* provided using the `rootSelectorOrNode` argument.
*
* If the target DOM element is not provided, Angular tries to find one on a page
* using the `selector` of the component that is being bootstrapped
* (first matched element is used).
*
* ### Example
*
* Generally, we define the component to bootstrap in the `bootstrap` array of `NgModule`,
* but it requires us to know the component while writing the application code.
*
* Imagine a situation where we have to wait for an API call to decide about the component to
* bootstrap. We can use the `ngDoBootstrap` hook of the `NgModule` and call this method to
* dynamically bootstrap a component.
*
* {@example core/ts/platform/platform.ts region='componentSelector'}
*
* Optionally, a component can be mounted onto a DOM element that does not match the
* selector of the bootstrapped component.
*
* In the following example, we are providing a CSS selector to match the target element.
*
* {@example core/ts/platform/platform.ts region='cssSelector'}
*
* While in this example, we are providing reference to a DOM node.
*
* {@example core/ts/platform/platform.ts region='domNode'}
*/
bootstrap<C>(
componentOrFactory: ComponentFactory<C> | Type<C>,
rootSelectorOrNode?: string | any,
): ComponentRef<C> {
return this.bootstrapImpl(componentOrFactory, rootSelectorOrNode);
}
private bootstrapImpl<C>(
component: Type<C>,
componentOrFactory: ComponentFactory<C> | Type<C>,
rootSelectorOrNode?: string | any,
injector: Injector = Injector.NULL,
): ComponentRef<C> {
@ -456,12 +504,13 @@ export class ApplicationRef {
profiler(ProfilerEvent.BootstrapComponentStart);
(typeof ngDevMode === 'undefined' || ngDevMode) && warnIfDestroyed(this._destroyed);
const isComponentFactory = componentOrFactory instanceof ComponentFactory;
const initStatus = this._injector.get(ApplicationInitStatus);
if (!initStatus.done) {
let errorMessage = '';
if (typeof ngDevMode === 'undefined' || ngDevMode) {
const standalone = isStandalone(component);
const standalone = !isComponentFactory && isStandalone(componentOrFactory);
errorMessage =
'Cannot bootstrap as there are still asynchronous initializers running.' +
(standalone
@ -471,8 +520,13 @@ export class ApplicationRef {
throw new RuntimeError(RuntimeErrorCode.ASYNC_INITIALIZERS_STILL_RUNNING, errorMessage);
}
const resolver = this._injector.get(ComponentFactoryResolver);
const componentFactory = resolver.resolveComponentFactory(component)!;
let componentFactory: ComponentFactory<C>;
if (isComponentFactory) {
componentFactory = componentOrFactory;
} else {
const resolver = this._injector.get(ComponentFactoryResolver);
componentFactory = resolver.resolveComponentFactory(componentOrFactory)!;
}
this.componentTypes.push(componentFactory.componentType);
// Create a factory associated with the current module if it's not bound to some other

View file

@ -14,8 +14,8 @@ export {
CompilerOptions,
ModuleWithComponentFactories,
} from './linker/compiler';
export {ComponentRef, ComponentFactory as ɵComponentFactory} from './linker/component_factory';
export {ComponentFactoryResolver as ɵComponentFactoryResolver} from './linker/component_factory_resolver';
export {ComponentFactory, ComponentRef} from './linker/component_factory';
export {ComponentFactoryResolver} from './linker/component_factory_resolver';
export {DestroyRef} from './linker/destroy_ref';
export {ElementRef} from './linker/element_ref';
export {NgModuleFactory, NgModuleRef} from './linker/ng_module_factory';

View file

@ -85,6 +85,11 @@ export abstract class ComponentRef<C> {
* Base class for a factory that can create a component dynamically.
* Instantiate a factory for a given type of component with `resolveComponentFactory()`.
* Use the resulting `ComponentFactory.create()` method to create a component of that type.
*
* @publicApi
*
* @deprecated Angular no longer requires Component factories. Please use other APIs where
* Component class can be used directly.
*/
export abstract class ComponentFactory<C> {
/**

View file

@ -32,6 +32,11 @@ class _NullComponentFactoryResolver implements ComponentFactoryResolver {
* Note: since v13, dynamic component creation via
* [`ViewContainerRef.createComponent`](api/core/ViewContainerRef#createComponent)
* does **not** require resolving component factory: component class can be used directly.
*
* @publicApi
*
* @deprecated Angular no longer requires Component factories. Please use other APIs where
* Component class can be used directly.
*/
export abstract class ComponentFactoryResolver {
static NULL: ComponentFactoryResolver = /* @__PURE__ */ new _NullComponentFactoryResolver();

View file

@ -17,7 +17,7 @@ import {
markRNodeAsClaimedByHydration,
} from '../hydration/utils';
import {findMatchingDehydratedView, locateDehydratedViewsInContainer} from '../hydration/views';
import {Type} from '../interface/type';
import {isType, Type} from '../interface/type';
import {assertNodeInjector} from '../render3/assert';
import {ComponentFactory as R3ComponentFactory} from '../render3/component_ref';
import {getComponentDef} from '../render3/def_getters';
@ -74,7 +74,7 @@ import {RuntimeError, RuntimeErrorCode} from '../errors';
import {Binding, DirectiveWithBindings} from '../render3/dynamic_bindings';
import {addToEndOfViewTree} from '../render3/view/construction';
import {addLViewToLContainer, createLContainer, detachView} from '../render3/view/container';
import {ComponentRef} from './component_factory';
import {ComponentFactory, ComponentRef} from './component_factory';
import {createElementRef, ElementRef} from './element_ref';
import {NgModuleRef} from './ng_module_factory';
import {TemplateRef} from './template_ref';
@ -244,6 +244,36 @@ export abstract class ViewContainerRef {
},
): ComponentRef<C>;
/**
* Instantiates a single component and inserts its host view into this container.
*
* @param componentFactory Component factory to use.
* @param index The index at which to insert the new component's host view into this container.
* If not specified, appends the new view as the last entry.
* @param injector The injector to use as the parent for the new component.
* @param projectableNodes List of DOM nodes that should be projected through
* [`<ng-content>`](api/core/ng-content) of the new component instance.
* @param ngModuleRef An instance of the NgModuleRef that represent an NgModule.
* This information is used to retrieve corresponding NgModule injector.
* @param directives Directives that should be applied to the component.
* @param bindings Bindings that should be applied to the component.
*
* @returns The new `ComponentRef` which contains the component instance and the host view.
*
* @deprecated Angular no longer requires component factories to dynamically create components.
* Use different signature of the `createComponent` method, which allows passing
* Component class directly.
*/
abstract createComponent<C>(
componentFactory: ComponentFactory<C>,
index?: number,
injector?: Injector,
projectableNodes?: any[][],
environmentInjector?: EnvironmentInjector | NgModuleRef<any>,
directives?: (Type<unknown> | DirectiveWithBindings<unknown>)[],
bindings?: Binding[],
): ComponentRef<C>;
/**
* Inserts a view into this container.
* @param viewRef The view to insert.
@ -405,63 +435,102 @@ class R3ViewContainerRef extends ViewContainerRef {
bindings?: Binding[];
},
): ComponentRef<C>;
/**
* @deprecated Angular no longer requires component factories to dynamically create components.
* Use different signature of the `createComponent` method, which allows passing
* Component class directly.
*/
override createComponent<C>(
componentType: Type<C>,
opts?: {
index?: number;
injector?: Injector;
ngModuleRef?: NgModuleRef<unknown>;
environmentInjector?: EnvironmentInjector | NgModuleRef<unknown>;
projectableNodes?: Node[][];
directives?: (Type<unknown> | DirectiveWithBindings<unknown>)[];
bindings?: Binding[];
},
componentFactory: ComponentFactory<C>,
index?: number | undefined,
injector?: Injector | undefined,
projectableNodes?: any[][] | undefined,
environmentInjector?: EnvironmentInjector | NgModuleRef<any> | undefined,
directives?: (Type<unknown> | DirectiveWithBindings<unknown>)[],
bindings?: Binding[],
): ComponentRef<C>;
override createComponent<C>(
componentFactoryOrType: ComponentFactory<C> | Type<C>,
indexOrOptions?:
| number
| undefined
| {
index?: number;
injector?: Injector;
ngModuleRef?: NgModuleRef<unknown>;
environmentInjector?: EnvironmentInjector | NgModuleRef<unknown>;
projectableNodes?: Node[][];
directives?: (Type<unknown> | DirectiveWithBindings<unknown>)[];
bindings?: Binding[];
},
injector?: Injector | undefined,
projectableNodes?: any[][] | undefined,
environmentInjector?: EnvironmentInjector | NgModuleRef<any> | undefined,
directives?: (Type<unknown> | DirectiveWithBindings<unknown>)[],
bindings?: Binding[],
): ComponentRef<C> {
const isComponentFactory = componentFactoryOrType && !isType(componentFactoryOrType);
let index: number | undefined;
if (ngDevMode) {
assertDefined(
getComponentDef(componentType),
`Provided Component class doesn't contain Component definition. ` +
`Please check whether provided class has @Component decorator.`,
);
assertEqual(
typeof opts !== 'number',
true,
'It looks like Component type was provided as the first argument ' +
"and a number (representing an index at which to insert the new component's " +
'host view into this container as the second argument. This combination of arguments ' +
'is incompatible. Please use an object as the second argument instead.',
);
// This function supports 2 signatures and we need to handle options correctly for both:
// 1. When first argument is a Component type. This signature also requires extra
// options to be provided as object (more ergonomic option).
// 2. First argument is a Component factory. In this case extra options are represented as
// positional arguments. This signature is less ergonomic and will be deprecated.
if (isComponentFactory) {
if (ngDevMode) {
assertEqual(
typeof indexOrOptions !== 'object',
true,
'It looks like Component factory was provided as the first argument ' +
'and an options object as the second argument. This combination of arguments ' +
'is incompatible. You can either change the first argument to provide Component ' +
'type or change the second argument to be a number (representing an index at ' +
"which to insert the new component's host view into this container)",
);
}
index = indexOrOptions as number | undefined;
} else {
if (ngDevMode) {
assertDefined(
getComponentDef(componentFactoryOrType),
`Provided Component class doesn't contain Component definition. ` +
`Please check whether provided class has @Component decorator.`,
);
assertEqual(
typeof indexOrOptions !== 'number',
true,
'It looks like Component type was provided as the first argument ' +
"and a number (representing an index at which to insert the new component's " +
'host view into this container as the second argument. This combination of arguments ' +
'is incompatible. Please use an object as the second argument instead.',
);
}
const options = (indexOrOptions || {}) as {
index?: number;
injector?: Injector;
ngModuleRef?: NgModuleRef<unknown>;
environmentInjector?: EnvironmentInjector | NgModuleRef<unknown>;
projectableNodes?: Node[][];
directives?: (Type<unknown> | DirectiveWithBindings<unknown>)[];
bindings?: Binding[];
};
if (ngDevMode && options.environmentInjector && options.ngModuleRef) {
throwError(
`Cannot pass both environmentInjector and ngModuleRef options to createComponent().`,
);
}
index = options.index;
injector = options.injector;
projectableNodes = options.projectableNodes;
environmentInjector = options.environmentInjector || options.ngModuleRef;
directives = options.directives;
bindings = options.bindings;
}
const options = (opts || {}) as {
index?: number;
injector?: Injector;
ngModuleRef?: NgModuleRef<unknown>;
environmentInjector?: EnvironmentInjector | NgModuleRef<unknown>;
projectableNodes?: Node[][];
directives?: (Type<unknown> | DirectiveWithBindings<unknown>)[];
bindings?: Binding[];
};
if (ngDevMode && options.environmentInjector && options.ngModuleRef) {
throwError(
`Cannot pass both environmentInjector and ngModuleRef options to createComponent().`,
);
}
index = options.index;
injector = options.injector;
projectableNodes = options.projectableNodes;
environmentInjector = options.environmentInjector || options.ngModuleRef;
directives = options.directives;
bindings = options.bindings;
const componentFactory = new R3ComponentFactory(getComponentDef(componentType)!);
const componentFactory: ComponentFactory<C> = isComponentFactory
? (componentFactoryOrType as ComponentFactory<C>)
: new R3ComponentFactory(getComponentDef(componentFactoryOrType)!);
const contextInjector = injector || this.parentInjector;
// If an `NgModuleRef` is not provided explicitly, try retrieving it from the DI tree.
@ -482,7 +551,7 @@ class R3ViewContainerRef extends ViewContainerRef {
// NgModule outside of a module tree). Instead, we always use `ViewContainerRef`'s parent
// injector, which is normally connected to the DI tree, which includes module injector
// subtree.
const _injector = this.parentInjector;
const _injector = isComponentFactory ? contextInjector : this.parentInjector;
// DO NOT REFACTOR. The code here used to have a `injector.get(NgModuleRef, null) ||
// undefined` expression which seems to cause internal google apps to fail. This is documented
@ -509,7 +578,7 @@ class R3ViewContainerRef extends ViewContainerRef {
index,
shouldAddViewToDom(this._hostTNode, dehydratedView),
);
return componentRef as ComponentRef<C>;
return componentRef;
}
override insert(viewRef: ViewRef, index?: number): ViewRef {

View file

@ -13,7 +13,6 @@ import {By, DomSanitizer} from '@angular/platform-browser';
import {expect} from '@angular/private/testing/matchers';
import {ANIMATION_QUEUE} from '../../src/animation/queue';
import {
ChangeDetectionStrategy,
ChangeDetectorRef,
Compiler,
Component,
@ -48,6 +47,7 @@ import {
ViewChildren,
ViewContainerRef,
ɵsetDocument,
ChangeDetectionStrategy,
} from '../../src/core';
import {ComponentFixture, TestBed, TestComponentRenderer} from '../../testing';
@ -1671,6 +1671,43 @@ describe('ViewContainerRef', () => {
componentRef.destroy();
});
it('should be compatible with componentRef generated via TestBed.createComponent in component factory', () => {
@Component({
selector: 'child',
template: `Child Component`,
standalone: false,
changeDetection: ChangeDetectionStrategy.Eager,
})
class Child {}
@Component({
selector: 'comp',
template: '<ng-template #ref></ng-template>',
standalone: false,
changeDetection: ChangeDetectionStrategy.Eager,
})
class Comp {
@ViewChild('ref', {read: ViewContainerRef, static: true})
viewContainerRef!: ViewContainerRef;
ngOnInit() {
const makeComponentFactory = (componentType: any) => ({
create: () => TestBed.createComponent(componentType).componentRef,
});
this.viewContainerRef.createComponent(makeComponentFactory(Child) as any);
}
}
TestBed.configureTestingModule({declarations: [Comp, Child]});
const fixture = TestBed.createComponent(Comp);
fixture.detectChanges();
expect(fixture.debugElement.nativeElement.innerHTML).toContain('Child Component');
});
it('should return ComponentRef with ChangeDetectorRef attached to root view', () => {
@Component({
selector: 'dynamic-cmp',

View file

@ -19,9 +19,11 @@ import {
APP_BOOTSTRAP_LISTENER,
APP_INITIALIZER,
ChangeDetectionStrategy,
Compiler,
Component,
DestroyRef,
EnvironmentInjector,
InjectionToken,
Injector,
LOCALE_ID,
NgModule,
@ -114,6 +116,62 @@ describe('bootstrap', () => {
return MyModule;
}
it('should bootstrap a component from a child module', waitForAsync(
inject([ApplicationRef, Compiler], (app: ApplicationRef, compiler: Compiler) => {
@Component({
selector: 'bootstrap-app',
template: '',
standalone: false,
})
class SomeComponent {}
const helloToken = new InjectionToken<string>('hello');
@NgModule({
providers: [{provide: helloToken, useValue: 'component'}],
declarations: [SomeComponent],
})
class SomeModule {}
createRootEl();
const modFactory = compiler.compileModuleSync(SomeModule);
const module = modFactory.create(TestBed.inject(Injector));
const cmpFactory = module.componentFactoryResolver.resolveComponentFactory(SomeComponent);
const component = app.bootstrap(cmpFactory);
// The component should see the child module providers
expect(component.injector.get(helloToken)).toEqual('component');
}),
));
it('should bootstrap a component with a custom selector', waitForAsync(
inject([ApplicationRef, Compiler], (app: ApplicationRef, compiler: Compiler) => {
@Component({
selector: 'bootstrap-app',
template: '',
standalone: false,
})
class SomeComponent {}
const helloToken = new InjectionToken<string>('hello');
@NgModule({
providers: [{provide: helloToken, useValue: 'component'}],
declarations: [SomeComponent],
})
class SomeModule {}
createRootEl('custom-selector');
const modFactory = compiler.compileModuleSync(SomeModule);
const module = modFactory.create(TestBed.inject(Injector));
const cmpFactory = module.componentFactoryResolver.resolveComponentFactory(SomeComponent);
const component = app.bootstrap(cmpFactory, 'custom-selector');
// The component should see the child module providers
expect(component.injector.get(helloToken)).toEqual('component');
}),
));
describe('ApplicationRef', () => {
beforeEach(async () => {
TestBed.configureTestingModule({

View file

@ -543,6 +543,7 @@
"isSubscriber",
"isSubscription",
"isTemplateNode",
"isType",
"isTypeProvider",
"isValidLink",
"isValueProvider",

View file

@ -783,6 +783,7 @@
"isSubscriber",
"isSubscription",
"isTemplateNode",
"isType",
"isTypeProvider",
"isValidLink",
"isValidatorFn",

View file

@ -777,6 +777,7 @@
"isSubscriber",
"isSubscription",
"isTemplateNode",
"isType",
"isTypeProvider",
"isValidLink",
"isValidatorFn",

View file

@ -864,6 +864,7 @@
"isSubscriber",
"isSubscription",
"isTemplateNode",
"isType",
"isTypeProvider",
"isUrlTree",
"isValidLink",

View file

@ -18,6 +18,7 @@ import {
Attribute,
Compiler,
Component,
ComponentFactory,
ComponentRef,
ContentChildren,
createComponent,
@ -1126,13 +1127,14 @@ describe('integration tests', function () {
imports: [RootModule],
}).createComponent(RootComp);
const compiler = TestBed.inject(Compiler);
const myCompFactory =
compiler.compileModuleAndAllComponentsSync(MyModule).componentFactories[0];
const myCompFactory = <ComponentFactory<MyComp>>(
compiler.compileModuleAndAllComponentsSync(MyModule).componentFactories[0]
);
// Note: the ComponentFactory was created directly via the compiler, i.e. it
// does not have an association to an NgModuleRef.
// -> expect the providers of the module that the view container belongs to.
const compRef = myCompFactory.create(compFixture.componentInstance.vc.injector);
const compRef = compFixture.componentInstance.vc.createComponent(myCompFactory);
expect(compRef.instance.someToken).toBe('someRootValue');
});
@ -1220,7 +1222,7 @@ describe('integration tests', function () {
// Note: MyComp was declared as entryComponent in MyModule,
// and we don't pass an explicit ModuleRef to the createComponent call.
// -> expect the providers of MyModule!
const compRef = myCompFactory.create(compFixture.componentInstance.vc.injector);
const compRef = compFixture.componentInstance.vc.createComponent(myCompFactory);
expect(compRef.instance.someToken).toBe('someValue');
});
});

View file

@ -6,9 +6,9 @@
* found in the LICENSE file at https://angular.dev/license
*/
import {getActiveConsumer} from '../../primitives/signals';
import {
Component,
ComponentFactoryResolver,
createComponent,
createEnvironmentInjector,
effect,
@ -24,6 +24,7 @@ import {
ViewChild,
ViewContainerRef,
} from '../../src/core';
import {getActiveConsumer} from '../../primitives/signals';
import {createInjector} from '../../src/di/create_injector';
import {TestBed} from '../../testing';
@ -87,10 +88,10 @@ describe('reactive safety', () => {
}
}
const environmentInjector = TestBed.inject(EnvironmentInjector);
expectNotToThrowInReactiveContext(() => {
createComponent(TestCmp, {environmentInjector});
});
const injector = TestBed.inject(EnvironmentInjector);
const resolver = TestBed.inject(ComponentFactoryResolver);
const factory = resolver.resolveComponentFactory(TestCmp);
expectNotToThrowInReactiveContext(() => factory.create(injector));
});
it('should be safe to flip @if to true', () => {

View file

@ -11,19 +11,19 @@ import type {} from 'zone.js';
import {
ApplicationRef,
ɵChangeDetectionScheduler as ChangeDetectionScheduler,
ɵComponentFactory as ComponentFactory,
ɵComponentFactoryResolver as ComponentFactoryResolver,
ComponentFactory,
ComponentFactoryResolver,
ComponentRef,
EventEmitter,
Injector,
NgZone,
Type,
ɵChangeDetectionScheduler as ChangeDetectionScheduler,
ɵNotificationSource as NotificationSource,
ɵViewRef as ViewRef,
ɵisViewDirty as isViewDirty,
ɵmarkForRefresh as markForRefresh,
NgZone,
ɵNotificationSource as NotificationSource,
OutputRef,
Type,
ɵViewRef as ViewRef,
} from '@angular/core';
import {merge, Observable, ReplaySubject} from 'rxjs';
import {switchMap} from 'rxjs/operators';

View file

@ -5,7 +5,7 @@
* 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 {ɵComponentFactoryResolver as ComponentFactoryResolver, Injector, Type} from '@angular/core';
import {ComponentFactoryResolver, Injector, Type} from '@angular/core';
/**
* Provide methods for scheduling the execution of a callback.

View file

@ -8,7 +8,7 @@
import {
Component,
ɵComponentFactoryResolver as ComponentFactoryResolver,
ComponentFactoryResolver,
destroyPlatform,
EventEmitter,
Input,

View file

@ -11,6 +11,7 @@ import {
ChangeDetectionStrategy,
Compiler,
Component,
ComponentFactoryResolver,
CUSTOM_ELEMENTS_SCHEMA,
Directive,
Inject,
@ -523,6 +524,16 @@ describe('public testing API', () => {
});
describe('overriding providers', () => {
describe('in core', () => {
it('ComponentFactoryResolver', () => {
const componentFactoryMock = jasmine.createSpyObj('componentFactory', [
'resolveComponentFactory',
]);
TestBed.overrideProvider(ComponentFactoryResolver, {useValue: componentFactoryMock});
expect(TestBed.inject(ComponentFactoryResolver)).toEqual(componentFactoryMock);
});
});
describe('in NgModules', () => {
it('should support useValue', () => {
TestBed.configureTestingModule({

View file

@ -6,13 +6,7 @@
* found in the LICENSE file at https://angular.dev/license
*/
import {
ɵComponentFactory as ComponentFactory,
ɵComponentFactoryResolver as ComponentFactoryResolver,
Injector,
NgZone,
Type,
} from '@angular/core';
import {ComponentFactory, ComponentFactoryResolver, Injector, NgZone, Type} from '@angular/core';
import {
IAnnotatedFunction,

View file

@ -9,19 +9,19 @@
import {
ApplicationRef,
ChangeDetectorRef,
ɵComponentFactory as ComponentFactory,
ComponentFactory,
ComponentRef,
type EventEmitter,
Injector,
type ɵInputSignalNode as InputSignalNode,
OnChanges,
type OutputEmitterRef,
ɵSIGNAL as SIGNAL,
SimpleChange,
SimpleChanges,
StaticProvider,
Testability,
TestabilityRegistry,
type OutputEmitterRef,
type ɵInputSignalNode as InputSignalNode,
ɵSIGNAL as SIGNAL,
} from '@angular/core';
import {

View file

@ -8,7 +8,7 @@
import {
Compiler,
Component,
ɵComponentFactory as ComponentFactory,
ComponentFactory,
Injector,
NgModule,
TestabilityRegistry,