Search code examples
angularangular-materialpopoverangular-cdkscrollable

Large Angular material popover should make the parent content scrollable


I have a popover in my project with some checkboxes listed below the other.

Right now everything is working fine, but when the screen's resolution is kinda small, the content gets chopped on the bottom and the parent container isn't scrollable, this only happens with CdkOverlay since it doesn't seem to affect the parent content when the popover is displayed, you can see a working example on this stackblitz

I can't share my main code but this is what I've tried on the stackblitz and it's pretty similar to my project:

 <div
  cdkScrollable
  style="height: 100px; overflow-y: auto; border: 1px solid green">
  <button
    (click)="isOpen = !isOpen"
    cdkOverlayOrigin
    #trigger="cdkOverlayOrigin">Show</button>
  <ng-template
    cdkConnectedOverlay
    [cdkConnectedOverlayOrigin]="trigger"
    [cdkConnectedOverlayOpen]="isOpen">
    Popover content 
  </ng-template>
</div>

As you can see on the link the parent won't get a scroll when the popover is open, how can I achieve that?


Solution

  • A cdk-overlay is attached outside the app

    if the only you want is change the "parent" you can do it in the (attach) event

    <!--see the template reference variable "anchor" 
        and the style="position:relative"-->
    <div #anchor
        style="position:relative;
        height: 100px; 
        overflow-y: auto; 
        border: 1px solid green ">
      <button (click)="isOpen = !isOpen" cdkOverlayOrigin #trigger="cdkOverlayOrigin">
        Show
      </button>
    
      <!--in attach event you pass the "anchor"-->
      <ng-template #template
        cdkConnectedOverlay
        (attach)="changeParent(anchor)"
        ...
      >
       ...
      </ng-template>
    

    The changeParent it's simply:

      //in constructor inject the Overlay service
      constructor(private overlay: Overlay) { }
    
      changeParent(el:any)
      {
        //get the "cdk-panel
        const container=(this.overlay as any)
                            ._overlayContainer.getContainerElement()
    
        //it's necessary change the position to "absolute"
        container.style.position='absolute'
    
        //and take account the position of the div
        const rect=el.getBoundingClientRect()
        container.style['margin-top']=-rect.top+'px'
        container.style['margin-left']=-rect.left+'px'
    
    
        //change the parent using appendChild
        el.appendChild(container);
      }
    

    A stackblitz