Skip to content

Commit ecae525

Browse files
committed
Revert "refactor(core): remove ComponentFactoryResolver & ComponentFactory from the api surface"
This reverts commit 9d76ac8. g3 cleanup not complete
1 parent 4a174b8 commit ecae525

21 files changed

Lines changed: 364 additions & 95 deletions

goldens/public-api/core/index.api.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,8 @@ export class ApplicationRef {
134134
constructor();
135135
attachView(viewRef: ViewRef): void;
136136
bootstrap<C>(component: Type<C>, rootSelectorOrNode?: string | any): ComponentRef<C>;
137+
// @deprecated
138+
bootstrap<C>(componentFactory: ComponentFactory<C>, rootSelectorOrNode?: string | any): ComponentRef<C>;
137139
readonly components: ComponentRef<any>[];
138140
readonly componentTypes: Type<any>[];
139141
destroy(): void;
@@ -291,6 +293,31 @@ export interface ComponentDecorator {
291293
new (obj: Component): Component;
292294
}
293295

296+
// @public @deprecated
297+
export abstract class ComponentFactory<C> {
298+
abstract get componentType(): Type<any>;
299+
abstract create(injector: Injector, projectableNodes?: any[][], rootSelectorOrNode?: string | any, environmentInjector?: EnvironmentInjector | NgModuleRef<any>, directives?: (Type<unknown> | DirectiveWithBindings<unknown>)[], bindings?: Binding[]): ComponentRef<C>;
300+
abstract get inputs(): {
301+
propName: string;
302+
templateName: string;
303+
transform?: (value: any) => any;
304+
isSignal: boolean;
305+
}[];
306+
abstract get ngContentSelectors(): string[];
307+
abstract get outputs(): {
308+
propName: string;
309+
templateName: string;
310+
}[];
311+
abstract get selector(): string;
312+
}
313+
314+
// @public @deprecated
315+
export abstract class ComponentFactoryResolver {
316+
// (undocumented)
317+
static NULL: ComponentFactoryResolver;
318+
abstract resolveComponentFactory<T>(component: Type<T>): ComponentFactory<T>;
319+
}
320+
294321
// @public
295322
export interface ComponentMirror<C> {
296323
get inputs(): ReadonlyArray<{
@@ -2045,6 +2072,8 @@ export abstract class ViewContainerRef {
20452072
directives?: (Type<unknown> | DirectiveWithBindings<unknown>)[];
20462073
bindings?: Binding[];
20472074
}): ComponentRef<C>;
2075+
// @deprecated
2076+
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>;
20482077
abstract createEmbeddedView<C>(templateRef: TemplateRef<C>, context?: C, options?: {
20492078
index?: number;
20502079
injector?: Injector;

packages/core/src/application/application_ref.ts

Lines changed: 66 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@ import '../util/ng_hmr_mode';
1010
import '../util/ng_jit_mode';
1111
import '../util/ng_server_mode';
1212

13-
import {type Observable, Subject, type Subscription} from 'rxjs';
14-
import {map} from 'rxjs/operators';
1513
import {
16-
getActiveConsumer,
1714
setActiveConsumer,
15+
getActiveConsumer,
1816
setThrowInvalidWriteToSignalError,
1917
} from '../../primitives/signals';
18+
import {type Observable, Subject, type Subscription} from 'rxjs';
19+
import {map} from 'rxjs/operators';
2020

2121
import {ZONELESS_ENABLED} from '../change_detection/scheduling/zoneless_scheduling';
2222
import {Console} from '../console';
@@ -25,8 +25,8 @@ import {Injectable} from '../di/injectable';
2525
import {InjectionToken} from '../di/injection_token';
2626
import {Injector} from '../di/injector';
2727
import {EnvironmentInjector, type R3Injector} from '../di/r3_injector';
28-
import {INTERNAL_APPLICATION_ERROR_HANDLER} from '../error_handler';
2928
import {formatRuntimeError, RuntimeError, RuntimeErrorCode} from '../errors';
29+
import {INTERNAL_APPLICATION_ERROR_HANDLER} from '../error_handler';
3030
import {Type} from '../interface/type';
3131
import {ComponentFactory, ComponentRef} from '../linker/component_factory';
3232
import {ComponentFactoryResolver} from '../linker/component_factory_resolver';
@@ -44,10 +44,10 @@ import {ViewRef as InternalViewRef} from '../render3/view_ref';
4444
import {TESTABILITY} from '../testability/testability';
4545
import {NgZone} from '../zone/ng_zone';
4646

47-
import {ProfilerEvent} from '../../primitives/devtools';
4847
import {profiler} from '../render3/profiler';
49-
import {isReactiveLViewConsumer} from '../render3/reactive_lview_consumer';
48+
import {ProfilerEvent} from '../../primitives/devtools';
5049
import {EffectScheduler} from '../render3/reactivity/root_effect_scheduler';
50+
import {isReactiveLViewConsumer} from '../render3/reactive_lview_consumer';
5151
import {ApplicationInitStatus} from './application_init';
5252
import {TracingAction, TracingService, TracingSnapshot} from './tracing';
5353

@@ -441,13 +441,61 @@ export class ApplicationRef {
441441
* While in this example, we are providing reference to a DOM node.
442442
*
443443
* {@example core/ts/platform/platform.ts region='domNode'}
444+
*
445+
* @deprecated Passing Component factories as the `Application.bootstrap` function argument is
446+
* deprecated. Pass Component Types instead.
444447
*/
445-
bootstrap<C>(component: Type<C>, rootSelectorOrNode?: string | any): ComponentRef<C> {
446-
return this.bootstrapImpl(component, rootSelectorOrNode);
448+
bootstrap<C>(
449+
componentFactory: ComponentFactory<C>,
450+
rootSelectorOrNode?: string | any,
451+
): ComponentRef<C>;
452+
453+
/**
454+
* Bootstrap a component onto the element identified by its selector or, optionally, to a
455+
* specified element.
456+
*
457+
* @usageNotes
458+
* ### Bootstrap process
459+
*
460+
* When bootstrapping a component, Angular mounts it onto a target DOM element
461+
* and kicks off automatic change detection. The target DOM element can be
462+
* provided using the `rootSelectorOrNode` argument.
463+
*
464+
* If the target DOM element is not provided, Angular tries to find one on a page
465+
* using the `selector` of the component that is being bootstrapped
466+
* (first matched element is used).
467+
*
468+
* ### Example
469+
*
470+
* Generally, we define the component to bootstrap in the `bootstrap` array of `NgModule`,
471+
* but it requires us to know the component while writing the application code.
472+
*
473+
* Imagine a situation where we have to wait for an API call to decide about the component to
474+
* bootstrap. We can use the `ngDoBootstrap` hook of the `NgModule` and call this method to
475+
* dynamically bootstrap a component.
476+
*
477+
* {@example core/ts/platform/platform.ts region='componentSelector'}
478+
*
479+
* Optionally, a component can be mounted onto a DOM element that does not match the
480+
* selector of the bootstrapped component.
481+
*
482+
* In the following example, we are providing a CSS selector to match the target element.
483+
*
484+
* {@example core/ts/platform/platform.ts region='cssSelector'}
485+
*
486+
* While in this example, we are providing reference to a DOM node.
487+
*
488+
* {@example core/ts/platform/platform.ts region='domNode'}
489+
*/
490+
bootstrap<C>(
491+
componentOrFactory: ComponentFactory<C> | Type<C>,
492+
rootSelectorOrNode?: string | any,
493+
): ComponentRef<C> {
494+
return this.bootstrapImpl(componentOrFactory, rootSelectorOrNode);
447495
}
448496

449497
private bootstrapImpl<C>(
450-
component: Type<C>,
498+
componentOrFactory: ComponentFactory<C> | Type<C>,
451499
rootSelectorOrNode?: string | any,
452500
injector: Injector = Injector.NULL,
453501
): ComponentRef<C> {
@@ -456,12 +504,13 @@ export class ApplicationRef {
456504
profiler(ProfilerEvent.BootstrapComponentStart);
457505

458506
(typeof ngDevMode === 'undefined' || ngDevMode) && warnIfDestroyed(this._destroyed);
507+
const isComponentFactory = componentOrFactory instanceof ComponentFactory;
459508
const initStatus = this._injector.get(ApplicationInitStatus);
460509

461510
if (!initStatus.done) {
462511
let errorMessage = '';
463512
if (typeof ngDevMode === 'undefined' || ngDevMode) {
464-
const standalone = isStandalone(component);
513+
const standalone = !isComponentFactory && isStandalone(componentOrFactory);
465514
errorMessage =
466515
'Cannot bootstrap as there are still asynchronous initializers running.' +
467516
(standalone
@@ -471,8 +520,13 @@ export class ApplicationRef {
471520
throw new RuntimeError(RuntimeErrorCode.ASYNC_INITIALIZERS_STILL_RUNNING, errorMessage);
472521
}
473522

474-
const resolver = this._injector.get(ComponentFactoryResolver);
475-
const componentFactory = resolver.resolveComponentFactory(component)!;
523+
let componentFactory: ComponentFactory<C>;
524+
if (isComponentFactory) {
525+
componentFactory = componentOrFactory;
526+
} else {
527+
const resolver = this._injector.get(ComponentFactoryResolver);
528+
componentFactory = resolver.resolveComponentFactory(componentOrFactory)!;
529+
}
476530
this.componentTypes.push(componentFactory.componentType);
477531

478532
// Create a factory associated with the current module if it's not bound to some other

packages/core/src/linker.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ export {
1414
CompilerOptions,
1515
ModuleWithComponentFactories,
1616
} from './linker/compiler';
17-
export {ComponentRef, ComponentFactory as ɵComponentFactory} from './linker/component_factory';
18-
export {ComponentFactoryResolver as ɵComponentFactoryResolver} from './linker/component_factory_resolver';
17+
export {ComponentFactory, ComponentRef} from './linker/component_factory';
18+
export {ComponentFactoryResolver} from './linker/component_factory_resolver';
1919
export {DestroyRef} from './linker/destroy_ref';
2020
export {ElementRef} from './linker/element_ref';
2121
export {NgModuleFactory, NgModuleRef} from './linker/ng_module_factory';

packages/core/src/linker/component_factory.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,11 @@ export abstract class ComponentRef<C> {
8585
* Base class for a factory that can create a component dynamically.
8686
* Instantiate a factory for a given type of component with `resolveComponentFactory()`.
8787
* Use the resulting `ComponentFactory.create()` method to create a component of that type.
88+
*
89+
* @publicApi
90+
*
91+
* @deprecated Angular no longer requires Component factories. Please use other APIs where
92+
* Component class can be used directly.
8893
*/
8994
export abstract class ComponentFactory<C> {
9095
/**

packages/core/src/linker/component_factory_resolver.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@ class _NullComponentFactoryResolver implements ComponentFactoryResolver {
3232
* Note: since v13, dynamic component creation via
3333
* [`ViewContainerRef.createComponent`](api/core/ViewContainerRef#createComponent)
3434
* does **not** require resolving component factory: component class can be used directly.
35+
*
36+
* @publicApi
37+
*
38+
* @deprecated Angular no longer requires Component factories. Please use other APIs where
39+
* Component class can be used directly.
3540
*/
3641
export abstract class ComponentFactoryResolver {
3742
static NULL: ComponentFactoryResolver = /* @__PURE__ */ new _NullComponentFactoryResolver();

0 commit comments

Comments
 (0)