Skip to content

Commit 136f5dd

Browse files
crisbetojelbourn
authored andcommitted
feat(portal): allow for custom ComponentFactoryResolver to be associated with portal (#12677)
Allows consumers to specify a their own `ComponentFactoryResolver` when creating a `ComponentPortal`. Previously we would only use the resolver from the `PortalOutlet`. Fixes #9712.
1 parent 2f76451 commit 136f5dd

File tree

3 files changed

+29
-4
lines changed

3 files changed

+29
-4
lines changed

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ export class DomPortalOutlet extends BasePortalOutlet {
3636
* @returns Reference to the created component.
3737
*/
3838
attachComponentPortal<T>(portal: ComponentPortal<T>): ComponentRef<T> {
39-
let componentFactory = this._componentFactoryResolver.resolveComponentFactory(portal.component);
39+
const resolver = portal.componentFactoryResolver || this._componentFactoryResolver;
40+
const componentFactory = resolver.resolveComponentFactory(portal.component);
4041
let componentRef: ComponentRef<T>;
4142

4243
// If the portal specifies a ViewContainerRef, we will use that as the attachment point

src/cdk/portal/portal.spec.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -322,8 +322,8 @@ describe('Portals', () => {
322322
let host: DomPortalOutlet;
323323
let injector: Injector;
324324
let appRef: ApplicationRef;
325-
326325
let deps = [ComponentFactoryResolver, Injector, ApplicationRef];
326+
327327
beforeEach(inject(deps, (dcl: ComponentFactoryResolver, i: Injector, ar: ApplicationRef) => {
328328
componentFactoryResolver = dcl;
329329
injector = i;
@@ -468,6 +468,21 @@ describe('Portals', () => {
468468

469469
expect(spy).toHaveBeenCalled();
470470
});
471+
472+
it('should use the `ComponentFactoryResolver` from the portal, if available', () => {
473+
const spy = jasmine.createSpy('resolveComponentFactorySpy');
474+
const portal = new ComponentPortal(PizzaMsg, undefined, undefined, {
475+
resolveComponentFactory: (...args: any[]) => {
476+
spy();
477+
return componentFactoryResolver.resolveComponentFactory
478+
.apply(componentFactoryResolver, args);
479+
}
480+
});
481+
482+
host.attachComponentPortal(portal);
483+
expect(spy).toHaveBeenCalled();
484+
});
485+
471486
});
472487
});
473488

src/cdk/portal/portal.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ import {
1212
ElementRef,
1313
ComponentRef,
1414
EmbeddedViewRef,
15-
Injector
15+
Injector,
16+
ComponentFactoryResolver,
1617
} from '@angular/core';
1718
import {
1819
throwNullPortalOutletError,
@@ -93,14 +94,22 @@ export class ComponentPortal<T> extends Portal<ComponentRef<T>> {
9394
/** [Optional] Injector used for the instantiation of the component. */
9495
injector?: Injector | null;
9596

97+
/**
98+
* Alternate `ComponentFactoryResolver` to use when resolving the associated component.
99+
* Defaults to using the resolver from the outlet that the portal is attached to.
100+
*/
101+
componentFactoryResolver?: ComponentFactoryResolver | null;
102+
96103
constructor(
97104
component: ComponentType<T>,
98105
viewContainerRef?: ViewContainerRef | null,
99-
injector?: Injector | null) {
106+
injector?: Injector | null,
107+
componentFactoryResolver?: ComponentFactoryResolver | null) {
100108
super();
101109
this.component = component;
102110
this.viewContainerRef = viewContainerRef;
103111
this.injector = injector;
112+
this.componentFactoryResolver = componentFactoryResolver;
104113
}
105114
}
106115

0 commit comments

Comments
 (0)