Skip to content

Commit 7a24e95

Browse files
authored
feat(cdk/portal): support projectableNodes in component portal (#25185)
Allows for the `projectableNodes` parameter to be used with a component portal. Fixes #9045.
1 parent e3f1585 commit 7a24e95

File tree

5 files changed

+28
-6
lines changed

5 files changed

+28
-6
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ export class DomPortalOutlet extends BasePortalOutlet {
7474
componentFactory,
7575
portal.viewContainerRef.length,
7676
portal.injector || portal.viewContainerRef.injector,
77+
portal.projectableNodes || undefined,
7778
);
7879

7980
this.setDisposeFn(() => componentRef.destroy());

src/cdk/portal/portal-directives.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,7 @@ export class CdkPortalOutlet extends BasePortalOutlet implements OnInit, OnDestr
133133

134134
ngOnDestroy() {
135135
super.dispose();
136-
this._attachedPortal = null;
137-
this._attachedRef = null;
136+
this._attachedRef = this._attachedPortal = null;
138137
}
139138

140139
/**
@@ -157,6 +156,7 @@ export class CdkPortalOutlet extends BasePortalOutlet implements OnInit, OnDestr
157156
componentFactory,
158157
viewContainerRef.length,
159158
portal.injector || viewContainerRef.injector,
159+
portal.projectableNodes || undefined,
160160
);
161161

162162
// If we're using a view container that's different from the injected one (e.g. when the portal

src/cdk/portal/portal.spec.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,19 @@ describe('Portals', () => {
450450

451451
expect(hostContainer.textContent).toContain('Pizza');
452452
});
453+
454+
it('should be able to pass projectable nodes to portal', () => {
455+
// Set the selectedHost to be a ComponentPortal.
456+
const testAppComponent = fixture.componentInstance;
457+
const componentPortal = new ComponentPortal(PizzaMsg, undefined, undefined, undefined, [
458+
[document.createTextNode('Projectable node')],
459+
]);
460+
461+
testAppComponent.selectedPortal = componentPortal;
462+
fixture.detectChanges();
463+
464+
expect(fixture.nativeElement.textContent).toContain('Projectable node');
465+
});
453466
});
454467

455468
describe('DomPortalOutlet', () => {
@@ -728,7 +741,7 @@ class ChocolateInjector {
728741
/** Simple component for testing ComponentPortal. */
729742
@Component({
730743
selector: 'pizza-msg',
731-
template: '<p>Pizza</p><p>{{snack}}</p>',
744+
template: '<p>Pizza</p><p>{{snack}}</p><ng-content></ng-content>',
732745
})
733746
class PizzaMsg {
734747
constructor(@Optional() public snack: Chocolate) {}

src/cdk/portal/portal.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,13 +86,13 @@ export class ComponentPortal<T> extends Portal<ComponentRef<T>> {
8686
component: ComponentType<T>;
8787

8888
/**
89-
* [Optional] Where the attached component should live in Angular's *logical* component tree.
89+
* Where the attached component should live in Angular's *logical* component tree.
9090
* This is different from where the component *renders*, which is determined by the PortalOutlet.
9191
* The origin is necessary when the host is outside of the Angular application context.
9292
*/
9393
viewContainerRef?: ViewContainerRef | null;
9494

95-
/** [Optional] Injector used for the instantiation of the component. */
95+
/** Injector used for the instantiation of the component. */
9696
injector?: Injector | null;
9797

9898
/**
@@ -101,17 +101,24 @@ export class ComponentPortal<T> extends Portal<ComponentRef<T>> {
101101
*/
102102
componentFactoryResolver?: ComponentFactoryResolver | null;
103103

104+
/**
105+
* List of DOM nodes that should be projected through `<ng-content>` of the attached component.
106+
*/
107+
projectableNodes?: Node[][] | null;
108+
104109
constructor(
105110
component: ComponentType<T>,
106111
viewContainerRef?: ViewContainerRef | null,
107112
injector?: Injector | null,
108113
componentFactoryResolver?: ComponentFactoryResolver | null,
114+
projectableNodes?: Node[][] | null,
109115
) {
110116
super();
111117
this.component = component;
112118
this.viewContainerRef = viewContainerRef;
113119
this.injector = injector;
114120
this.componentFactoryResolver = componentFactoryResolver;
121+
this.projectableNodes = projectableNodes;
115122
}
116123
}
117124

tools/public_api_guard/cdk/portal.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,10 +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);
81+
constructor(component: ComponentType<T>, viewContainerRef?: ViewContainerRef | null, injector?: Injector | null, componentFactoryResolver?: ComponentFactoryResolver | null, projectableNodes?: Node[][] | null);
8282
component: ComponentType<T>;
8383
componentFactoryResolver?: ComponentFactoryResolver | null;
8484
injector?: Injector | null;
85+
projectableNodes?: Node[][] | null;
8586
viewContainerRef?: ViewContainerRef | null;
8687
}
8788

0 commit comments

Comments
 (0)