Supplying component for a CDK Overlay in 2 different ways

71 Views Asked by At

I've got an interesting situation for our component library that we just can't fully solve.

We have a component called banner that can show as a warning or info inline in the app.

We'd also like to be able to show this banner as an overlay toast type of experience but reuse the same component.

We want to be able to supply it to a service in 2 different ways, one is directly from a template of any component that has a reference to it. And the other is by referencing the Component import.

For the first way the best way we came up with is to have a wrapper element banner-overlay

The template of this wrapping component looks like this:

<ng-template #foo>
  <div class="banner-overlay">
    <ng-content select="banner[type=warning]"></ng-content>
  </div>
</ng-template>

The ts file looks like this:

@Component({
  selector: 'banner-overlay',
  templateUrl: './banner-overlay.component.html',
  styleUrls: ['./banner-overlay.component.css'],
  imports: [CommonModule, PortalModule],
  standalone: true,
})
export class BannerOverlayComponent implements OnInit {
  @ViewChild('foo', { static: true }) tmpl!: TemplateRef<any>;

  constructor(public vcr: ViewContainerRef) {}

}

It can be used like this in a given template:

<banner-container #container>
  <banner >
    Projected content
  </banner>
</banner-container>

The the ts file can grab it:

@ViewChild('container', { static: true })
  bannerOverlay!: BannerOverlayComponent;

Once we need to display the already referenced Overlay we can call the service with this method:

createBanner(item: BannerOverlayComponent) {
    const overlayRef = this._createOverlay();

    const portal = new TemplatePortal(item.tmpl, item.vcr);

    overlayRef.attach(portal);
  }

This works and feels pretty good and straight forward for other devs.

Where we are struggling is how to have a component such as FooBannerOverlay with a template like this:

<banner>
   projected content
</banner>

With the intent being that a developer can pass in a reference to this component class and not have to go put this in a template and then grab the reference to the template but that it could try to do some lifting for the dev and auto-wrap it with the BannerOverlay component. Then it could utilize CDK ComponentPortal/TemplatePortal to generate the portal.

I've tried lots of things with the new createComponent stuff. It kind of worked but content projection was wonky and felt very un-Angular to be supplying native nodes.

Any ideas or things I haven't thought of?

0

There are 0 best solutions below