Search code examples
javascriptangularangular-materialangular-cdk

Angular CDK Overlay, change default overlay container


Is there a way to change the OverlayContainer?

I have created a tooltip component, but sometimes I want to attach the overlay to a specific element (by default the overlay is attached to the document body).

Here is how I am creating the overlay:

  private initOverlay(): void {
    const positionStrategy = this.overlayPositionBuilder
      .flexibleConnectedTo(this.elementRef)
      .withPositions([this.resolvedConfig]);

    this.overlayRef = this.overlay.create({positionStrategy});
  }

And this is how I am attaching a template to it:

  show(): void {
    this.overlayRef.attach(new TemplatePortal(this.tpl, this.viewContainerRef));
  }

Solution

  • Please reference this stackblitz example.

    looks like you can accomplish this by extending the OverlayContainer class via the following in app.module.ts

    { provide: OverlayContainer, useFactory: () => new AppOverlayContainer() }

    Stackblitz

    https://stackblitz.com/edit/angular-material2-issue-ansnt5?file=app%2Fapp.module.ts


    This GitHub comment also provides an example of how to package this in a directive

    GitHub comment

    https://github.com/angular/material2/issues/7349#issuecomment-337513040


    Revision 3/22/19 working directive example

    Extend the OverlayContainer class via cdk-overlay-container.ts

    Stub the class in app.module.ts

      providers: [
        { provide: OverlayContainer, useClass: CdkOverlayContainer },
      ]
    

    In your cdk-overlay-container.ts you are preventing the default _createContainer() from working, and providing your own custom public method myCreateContainer to replace it.

    You are essentially creating an empty div here, adding a custom class to it my-custom-overlay-container-class and appending it to the div the directive is attached to, then passing that container to the private variable _containerElement in the true OverlayContainer class.

    /**
    * Create overlay container and append to ElementRef from directive
    */ 
    public myCreateContainer(element: HTMLElement): void {
       let container = document.createElement('div');
       container.classList.add('my-custom-overlay-container-class');
    
       element.appendChild(container);
       this._containerElement = container;
     }
     /**
      * Prevent creation of the HTML element, use custom method above
      */
     protected _createContainer(): void {
         return;
     }
    

    Then in your cdk-overlay-container.directive.ts your are calling myCreateContainer() and passing the ElementRef as an argument.

     this.cdkOverlayContainer['myCreateContainer'](this.elementReference.nativeElement);
    

    Then in your HTML assign the directive where you want it to show up.

    <div myCdkOverlayContainer 
    

    Stackblitz

    https://stackblitz.com/edit/angular-material2-issue-6nzwws?embed=1&file=app/app.component.html