Skip to content

Commit

Permalink
feat(cdk/portal): support projectableNodes in component portal (#25185)
Browse files Browse the repository at this point in the history
Allows for the `projectableNodes` parameter to be used with a component portal.

Fixes #9045.
  • Loading branch information
crisbeto committed Jun 29, 2022
1 parent e3f1585 commit 7a24e95
Show file tree
Hide file tree
Showing 5 changed files with 28 additions and 6 deletions.
1 change: 1 addition & 0 deletions src/cdk/portal/dom-portal-outlet.ts
Expand Up @@ -74,6 +74,7 @@ export class DomPortalOutlet extends BasePortalOutlet {
componentFactory,
portal.viewContainerRef.length,
portal.injector || portal.viewContainerRef.injector,
portal.projectableNodes || undefined,
);

this.setDisposeFn(() => componentRef.destroy());
Expand Down
4 changes: 2 additions & 2 deletions src/cdk/portal/portal-directives.ts
Expand Up @@ -133,8 +133,7 @@ export class CdkPortalOutlet extends BasePortalOutlet implements OnInit, OnDestr

ngOnDestroy() {
super.dispose();
this._attachedPortal = null;
this._attachedRef = null;
this._attachedRef = this._attachedPortal = null;
}

/**
Expand All @@ -157,6 +156,7 @@ export class CdkPortalOutlet extends BasePortalOutlet implements OnInit, OnDestr
componentFactory,
viewContainerRef.length,
portal.injector || viewContainerRef.injector,
portal.projectableNodes || undefined,
);

// If we're using a view container that's different from the injected one (e.g. when the portal
Expand Down
15 changes: 14 additions & 1 deletion src/cdk/portal/portal.spec.ts
Expand Up @@ -450,6 +450,19 @@ describe('Portals', () => {

expect(hostContainer.textContent).toContain('Pizza');
});

it('should be able to pass projectable nodes to portal', () => {
// Set the selectedHost to be a ComponentPortal.
const testAppComponent = fixture.componentInstance;
const componentPortal = new ComponentPortal(PizzaMsg, undefined, undefined, undefined, [
[document.createTextNode('Projectable node')],
]);

testAppComponent.selectedPortal = componentPortal;
fixture.detectChanges();

expect(fixture.nativeElement.textContent).toContain('Projectable node');
});
});

describe('DomPortalOutlet', () => {
Expand Down Expand Up @@ -728,7 +741,7 @@ class ChocolateInjector {
/** Simple component for testing ComponentPortal. */
@Component({
selector: 'pizza-msg',
template: '<p>Pizza</p><p>{{snack}}</p>',
template: '<p>Pizza</p><p>{{snack}}</p><ng-content></ng-content>',
})
class PizzaMsg {
constructor(@Optional() public snack: Chocolate) {}
Expand Down
11 changes: 9 additions & 2 deletions src/cdk/portal/portal.ts
Expand Up @@ -86,13 +86,13 @@ export class ComponentPortal<T> extends Portal<ComponentRef<T>> {
component: ComponentType<T>;

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

/** [Optional] Injector used for the instantiation of the component. */
/** Injector used for the instantiation of the component. */
injector?: Injector | null;

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

/**
* List of DOM nodes that should be projected through `<ng-content>` of the attached component.
*/
projectableNodes?: Node[][] | null;

constructor(
component: ComponentType<T>,
viewContainerRef?: ViewContainerRef | null,
injector?: Injector | null,
componentFactoryResolver?: ComponentFactoryResolver | null,
projectableNodes?: Node[][] | null,
) {
super();
this.component = component;
this.viewContainerRef = viewContainerRef;
this.injector = injector;
this.componentFactoryResolver = componentFactoryResolver;
this.projectableNodes = projectableNodes;
}
}

Expand Down
3 changes: 2 additions & 1 deletion tools/public_api_guard/cdk/portal.md
Expand Up @@ -78,10 +78,11 @@ export type CdkPortalOutletAttachedRef = ComponentRef<any> | EmbeddedViewRef<any

// @public
export class ComponentPortal<T> extends Portal<ComponentRef<T>> {
constructor(component: ComponentType<T>, viewContainerRef?: ViewContainerRef | null, injector?: Injector | null, componentFactoryResolver?: ComponentFactoryResolver | null);
constructor(component: ComponentType<T>, viewContainerRef?: ViewContainerRef | null, injector?: Injector | null, componentFactoryResolver?: ComponentFactoryResolver | null, projectableNodes?: Node[][] | null);
component: ComponentType<T>;
componentFactoryResolver?: ComponentFactoryResolver | null;
injector?: Injector | null;
projectableNodes?: Node[][] | null;
viewContainerRef?: ViewContainerRef | null;
}

Expand Down

0 comments on commit 7a24e95

Please sign in to comment.