Skip to content

Commit f83b846

Browse files
committed
fix(cdk/portal): remove ComponentFactoryResolver usages
We now have all the necessary APIs to allow to remove our usages of the deprecated `ComponentFactoryResolver`. Fixes #24334.
1 parent 7c8a796 commit f83b846

File tree

7 files changed

+48
-117
lines changed

7 files changed

+48
-117
lines changed

src/cdk/portal/dom-portal-outlet.ts

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@
88

99
import {
1010
ApplicationRef,
11-
ComponentFactoryResolver,
1211
ComponentRef,
1312
EmbeddedViewRef,
1413
Injector,
14+
createComponent,
1515
} from '@angular/core';
1616
import {BasePortalOutlet, ComponentPortal, DomPortal, TemplatePortal} from './portal';
1717

@@ -36,7 +36,11 @@ export class DomPortalOutlet extends BasePortalOutlet {
3636
constructor(
3737
/** Element into which the content is projected. */
3838
public outletElement: Element,
39-
private _componentFactoryResolver?: ComponentFactoryResolver,
39+
/**
40+
* @deprecated No longer in use. To be removed.
41+
* @breaking-change 18.0.0
42+
*/
43+
_componentFactoryResolver?: any,
4044
private _appRef?: ApplicationRef,
4145
private _defaultInjector?: Injector,
4246

@@ -51,41 +55,36 @@ export class DomPortalOutlet extends BasePortalOutlet {
5155
}
5256

5357
/**
54-
* Attach the given ComponentPortal to DOM element using the ComponentFactoryResolver.
58+
* Attach the given ComponentPortal to DOM element.
5559
* @param portal Portal to be attached
5660
* @returns Reference to the created component.
5761
*/
5862
attachComponentPortal<T>(portal: ComponentPortal<T>): ComponentRef<T> {
59-
const resolver = (portal.componentFactoryResolver || this._componentFactoryResolver)!;
60-
61-
if ((typeof ngDevMode === 'undefined' || ngDevMode) && !resolver) {
62-
throw Error('Cannot attach component portal to outlet without a ComponentFactoryResolver.');
63-
}
64-
65-
const componentFactory = resolver.resolveComponentFactory(portal.component);
6663
let componentRef: ComponentRef<T>;
6764

6865
// If the portal specifies a ViewContainerRef, we will use that as the attachment point
6966
// for the component (in terms of Angular's component tree, not rendering).
7067
// When the ViewContainerRef is missing, we use the factory to create the component directly
7168
// and then manually attach the view to the application.
7269
if (portal.viewContainerRef) {
73-
componentRef = portal.viewContainerRef.createComponent(
74-
componentFactory,
75-
portal.viewContainerRef.length,
76-
portal.injector || portal.viewContainerRef.injector,
77-
portal.projectableNodes || undefined,
78-
);
70+
componentRef = portal.viewContainerRef.createComponent(portal.component, {
71+
index: portal.viewContainerRef.length,
72+
injector: portal.injector || portal.viewContainerRef.injector,
73+
projectableNodes: portal.projectableNodes || undefined,
74+
});
7975

8076
this.setDisposeFn(() => componentRef.destroy());
8177
} else {
8278
if ((typeof ngDevMode === 'undefined' || ngDevMode) && !this._appRef) {
8379
throw Error('Cannot attach component portal to outlet without an ApplicationRef.');
8480
}
8581

86-
componentRef = componentFactory.create(
87-
portal.injector || this._defaultInjector || Injector.NULL,
88-
);
82+
componentRef = createComponent(portal.component, {
83+
elementInjector: portal.injector || this._defaultInjector || Injector.NULL,
84+
environmentInjector: this._appRef!.injector,
85+
projectableNodes: portal.projectableNodes || undefined,
86+
});
87+
8988
this._appRef!.attachView(componentRef.hostView);
9089
this.setDisposeFn(() => {
9190
// Verify that the ApplicationRef has registered views before trying to detach a host view.

src/cdk/portal/portal-directives.ts

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
*/
88

99
import {
10-
ComponentFactoryResolver,
1110
ComponentRef,
1211
Directive,
1312
EmbeddedViewRef,
@@ -80,7 +79,11 @@ export class CdkPortalOutlet extends BasePortalOutlet implements OnInit, OnDestr
8079
private _attachedRef: CdkPortalOutletAttachedRef;
8180

8281
constructor(
83-
private _componentFactoryResolver: ComponentFactoryResolver,
82+
/**
83+
* @deprecated `_componentFactoryResolver` parameter no longer in use. To be removed.
84+
* @breaking-change 18.0.0
85+
*/
86+
@Inject(DOCUMENT) _componentFactoryResolver: any,
8487
private _viewContainerRef: ViewContainerRef,
8588

8689
/**
@@ -137,7 +140,7 @@ export class CdkPortalOutlet extends BasePortalOutlet implements OnInit, OnDestr
137140
}
138141

139142
/**
140-
* Attach the given ComponentPortal to this PortalOutlet using the ComponentFactoryResolver.
143+
* Attach the given ComponentPortal to this PortalOutlet.
141144
*
142145
* @param portal Portal to be attached to the portal outlet.
143146
* @returns Reference to the created component.
@@ -150,14 +153,11 @@ export class CdkPortalOutlet extends BasePortalOutlet implements OnInit, OnDestr
150153
const viewContainerRef =
151154
portal.viewContainerRef != null ? portal.viewContainerRef : this._viewContainerRef;
152155

153-
const resolver = portal.componentFactoryResolver || this._componentFactoryResolver;
154-
const componentFactory = resolver.resolveComponentFactory(portal.component);
155-
const ref = viewContainerRef.createComponent(
156-
componentFactory,
157-
viewContainerRef.length,
158-
portal.injector || viewContainerRef.injector,
159-
portal.projectableNodes || undefined,
160-
);
156+
const ref = viewContainerRef.createComponent(portal.component, {
157+
index: viewContainerRef.length,
158+
injector: portal.injector || viewContainerRef.injector,
159+
projectableNodes: portal.projectableNodes || undefined,
160+
});
161161

162162
// If we're using a view container that's different from the injected one (e.g. when the portal
163163
// specifies its own) we need to move the component into the outlet, otherwise it'll be rendered

src/cdk/portal/portal.spec.ts

Lines changed: 3 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import {CommonModule} from '@angular/common';
22
import {
33
ApplicationRef,
44
Component,
5-
ComponentFactoryResolver,
65
ComponentRef,
76
ElementRef,
87
Injector,
@@ -37,15 +36,10 @@ describe('Portals', () => {
3736

3837
describe('CdkPortalOutlet', () => {
3938
let fixture: ComponentFixture<PortalTestApp>;
40-
let componentFactoryResolver: ComponentFactoryResolver;
4139

4240
beforeEach(() => {
4341
fixture = TestBed.createComponent(PortalTestApp);
4442
fixture.detectChanges();
45-
46-
inject([ComponentFactoryResolver], (cfr: ComponentFactoryResolver) => {
47-
componentFactoryResolver = cfr;
48-
})();
4943
});
5044

5145
it('should load a component into the portal', () => {
@@ -428,19 +422,6 @@ describe('Portals', () => {
428422
expect(instance.portalOutlet.hasAttached()).toBe(true);
429423
});
430424

431-
it('should use the `ComponentFactoryResolver` from the portal, if available', () => {
432-
const spy = jasmine.createSpy('resolveComponentFactorySpy');
433-
const portal = new ComponentPortal(PizzaMsg, undefined, undefined, {
434-
resolveComponentFactory: <T>(...args: [Type<T>]) => {
435-
spy();
436-
return componentFactoryResolver.resolveComponentFactory(...args);
437-
},
438-
});
439-
440-
fixture.componentInstance.portalOutlet.attachComponentPortal(portal);
441-
expect(spy).toHaveBeenCalled();
442-
});
443-
444425
it('should render inside outlet when component portal specifies view container ref', () => {
445426
const hostContainer = fixture.nativeElement.querySelector('.portal-container');
446427
const portal = new ComponentPortal(PizzaMsg, fixture.componentInstance.alternateContainer);
@@ -466,32 +447,23 @@ describe('Portals', () => {
466447
});
467448

468449
describe('DomPortalOutlet', () => {
469-
let componentFactoryResolver: ComponentFactoryResolver;
470450
let someViewContainerRef: ViewContainerRef;
471451
let someInjector: Injector;
472452
let someFixture: ComponentFixture<ArbitraryViewContainerRefComponent>;
473453
let someDomElement: HTMLElement;
474454
let host: DomPortalOutlet;
475455
let injector: Injector;
476456
let appRef: ApplicationRef;
477-
let deps = [ComponentFactoryResolver, Injector, ApplicationRef];
457+
let deps = [Injector, ApplicationRef];
478458

479-
beforeEach(inject(deps, (cfr: ComponentFactoryResolver, i: Injector, ar: ApplicationRef) => {
480-
componentFactoryResolver = cfr;
459+
beforeEach(inject(deps, (i: Injector, ar: ApplicationRef) => {
481460
injector = i;
482461
appRef = ar;
483462
}));
484463

485464
beforeEach(() => {
486465
someDomElement = document.createElement('div');
487-
host = new DomPortalOutlet(
488-
someDomElement,
489-
componentFactoryResolver,
490-
appRef,
491-
injector,
492-
document,
493-
);
494-
466+
host = new DomPortalOutlet(someDomElement, null, appRef, injector, document);
495467
someFixture = TestBed.createComponent(ArbitraryViewContainerRefComponent);
496468
someViewContainerRef = someFixture.componentInstance.viewContainerRef;
497469
someInjector = someFixture.componentInstance.injector;
@@ -647,19 +619,6 @@ describe('Portals', () => {
647619
expect(spy).toHaveBeenCalled();
648620
});
649621

650-
it('should use the `ComponentFactoryResolver` from the portal, if available', () => {
651-
const spy = jasmine.createSpy('resolveComponentFactorySpy');
652-
const portal = new ComponentPortal(PizzaMsg, undefined, undefined, {
653-
resolveComponentFactory: <T>(...args: [Type<T>]) => {
654-
spy();
655-
return componentFactoryResolver.resolveComponentFactory(...args);
656-
},
657-
});
658-
659-
host.attachComponentPortal(portal);
660-
expect(spy).toHaveBeenCalled();
661-
});
662-
663622
it('should attach and detach a DOM portal', () => {
664623
const fixture = TestBed.createComponent(PortalTestApp);
665624
fixture.detectChanges();

src/cdk/portal/portal.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import {
1313
ComponentRef,
1414
EmbeddedViewRef,
1515
Injector,
16-
ComponentFactoryResolver,
1716
} from '@angular/core';
1817
import {
1918
throwNullPortalOutletError,
@@ -96,10 +95,10 @@ export class ComponentPortal<T> extends Portal<ComponentRef<T>> {
9695
injector?: Injector | null;
9796

9897
/**
99-
* Alternate `ComponentFactoryResolver` to use when resolving the associated component.
100-
* Defaults to using the resolver from the outlet that the portal is attached to.
98+
* @deprecated No longer in use. To be removed.
99+
* @breaking-change 18.0.0
101100
*/
102-
componentFactoryResolver?: ComponentFactoryResolver | null;
101+
componentFactoryResolver?: any;
103102

104103
/**
105104
* List of DOM nodes that should be projected through `<ng-content>` of the attached component.
@@ -110,14 +109,17 @@ export class ComponentPortal<T> extends Portal<ComponentRef<T>> {
110109
component: ComponentType<T>,
111110
viewContainerRef?: ViewContainerRef | null,
112111
injector?: Injector | null,
113-
componentFactoryResolver?: ComponentFactoryResolver | null,
112+
/**
113+
* @deprecated No longer in use. To be removed.
114+
* @breaking-change 18.0.0
115+
*/
116+
_componentFactoryResolver?: any,
114117
projectableNodes?: Node[][] | null,
115118
) {
116119
super();
117120
this.component = component;
118121
this.viewContainerRef = viewContainerRef;
119122
this.injector = injector;
120-
this.componentFactoryResolver = componentFactoryResolver;
121123
this.projectableNodes = projectableNodes;
122124
}
123125
}

src/material/dialog/dialog.spec.ts

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import {SpyLocation} from '@angular/common/testing';
1616
import {
1717
ChangeDetectionStrategy,
1818
Component,
19-
ComponentFactoryResolver,
2019
createNgModuleRef,
2120
Directive,
2221
Inject,
@@ -754,21 +753,6 @@ describe('MDC-based MatDialog', () => {
754753
expect(scrollStrategy.enable).toHaveBeenCalled();
755754
}));
756755

757-
it('should be able to pass in an alternate ComponentFactoryResolver', inject(
758-
[ComponentFactoryResolver],
759-
(resolver: ComponentFactoryResolver) => {
760-
spyOn(resolver, 'resolveComponentFactory').and.callThrough();
761-
762-
dialog.open(PizzaMsg, {
763-
viewContainerRef: testViewContainerRef,
764-
componentFactoryResolver: resolver,
765-
});
766-
viewContainerFixture.detectChanges();
767-
768-
expect(resolver.resolveComponentFactory).toHaveBeenCalled();
769-
},
770-
));
771-
772756
describe('passing in data', () => {
773757
it('should be able to pass in data', () => {
774758
let config = {data: {stringParam: 'hello', dateParam: new Date()}};

src/material/legacy-dialog/dialog.spec.ts

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import {
1717
TemplateRef,
1818
ViewChild,
1919
ViewContainerRef,
20-
ComponentFactoryResolver,
2120
NgZone,
2221
ViewEncapsulation,
2322
Injectable,
@@ -813,21 +812,6 @@ describe('MatDialog', () => {
813812
expect(scrollStrategy.enable).toHaveBeenCalled();
814813
}));
815814

816-
it('should be able to pass in an alternate ComponentFactoryResolver', inject(
817-
[ComponentFactoryResolver],
818-
(resolver: ComponentFactoryResolver) => {
819-
spyOn(resolver, 'resolveComponentFactory').and.callThrough();
820-
821-
dialog.open(PizzaMsg, {
822-
viewContainerRef: testViewContainerRef,
823-
componentFactoryResolver: resolver,
824-
});
825-
viewContainerFixture.detectChanges();
826-
827-
expect(resolver.resolveComponentFactory).toHaveBeenCalled();
828-
},
829-
));
830-
831815
describe('passing in data', () => {
832816
it('should be able to pass in data', () => {
833817
const config = {

tools/public_api_guard/cdk/portal.md

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
```ts
66

77
import { ApplicationRef } from '@angular/core';
8-
import { ComponentFactoryResolver } from '@angular/core';
98
import { ComponentRef } from '@angular/core';
109
import { ElementRef } from '@angular/core';
1110
import { EmbeddedViewRef } from '@angular/core';
@@ -53,7 +52,8 @@ export class CdkPortal extends TemplatePortal {
5352

5453
// @public
5554
export class CdkPortalOutlet extends BasePortalOutlet implements OnInit, OnDestroy {
56-
constructor(_componentFactoryResolver: ComponentFactoryResolver, _viewContainerRef: ViewContainerRef,
55+
constructor(
56+
_componentFactoryResolver: any, _viewContainerRef: ViewContainerRef,
5757
_document?: any);
5858
attachComponentPortal<T>(portal: ComponentPortal<T>): ComponentRef<T>;
5959
// @deprecated
@@ -78,9 +78,11 @@ export type CdkPortalOutletAttachedRef = ComponentRef<any> | EmbeddedViewRef<any
7878

7979
// @public
8080
export class ComponentPortal<T> extends Portal<ComponentRef<T>> {
81-
constructor(component: ComponentType<T>, viewContainerRef?: ViewContainerRef | null, injector?: Injector | null, componentFactoryResolver?: ComponentFactoryResolver | null, projectableNodes?: Node[][] | null);
81+
constructor(component: ComponentType<T>, viewContainerRef?: ViewContainerRef | null, injector?: Injector | null,
82+
_componentFactoryResolver?: any, projectableNodes?: Node[][] | null);
8283
component: ComponentType<T>;
83-
componentFactoryResolver?: ComponentFactoryResolver | null;
84+
// @deprecated (undocumented)
85+
componentFactoryResolver?: any;
8486
injector?: Injector | null;
8587
projectableNodes?: Node[][] | null;
8688
viewContainerRef?: ViewContainerRef | null;
@@ -105,7 +107,8 @@ export class DomPortalHost extends DomPortalOutlet {
105107
// @public
106108
export class DomPortalOutlet extends BasePortalOutlet {
107109
constructor(
108-
outletElement: Element, _componentFactoryResolver?: ComponentFactoryResolver | undefined, _appRef?: ApplicationRef | undefined, _defaultInjector?: Injector | undefined,
110+
outletElement: Element,
111+
_componentFactoryResolver?: any, _appRef?: ApplicationRef | undefined, _defaultInjector?: Injector | undefined,
109112
_document?: any);
110113
attachComponentPortal<T>(portal: ComponentPortal<T>): ComponentRef<T>;
111114
// @deprecated

0 commit comments

Comments
 (0)