Angular CDK understanding the overlay position system

David Rinck did a great job answering, what ended up working for me was using the template directives directly and not even getting into typescript overlay references ( overlay.postition / manually attaching/detaching etc.).

Here's an example where I create a modal that sits below a button I have. It was behaving oddly without setting positions explicitly, so I had to implement the positions array.

html:

<button cdkOverlayOrigin
        #trigger="cdkOverlayOrigin"
        (click)="isOpen = true">
  View Menu
</button>


<ng-template
    [cdkConnectedOverlayPanelClass]="'pm-responsive-text'"
    *ngIf="filterGroup?.filters?.length > numberOfVisibleFilters"
    cdkConnectedOverlay
    cdkConnectedOverlayPush ----- this pushes things on screen
    [cdkConnectedOverlayPositions]="positionPairs"
    [cdkConnectedOverlayOrigin]="filterTrigger"
    [cdkConnectedOverlayOpen]="isOpen"
    [cdkConnectedOverlayHasBackdrop]="true"
    (backdropClick)="isOpen = false">
    <div>...my modal code....</div>
</ng-template>

ts:

 // from my testing it doesn't seem to want to switch positions when 
 // resizing so I went ahead and just set it to the position I wanted and 
 // relied on cdkConnectedOverlayPush to handle the rest
positionPairs: ConnectionPositionPair[] = [
    {
      offsetX: 0,
      offsetY: 165,
      originX: 'start',
      originY: 'bottom',
      overlayX: 'start',
      overlayY: 'bottom',
      panelClass: null,
    },
  ];

There still isn't much documentation about the Angular Overlay CDK. Most of what I've learned has come from their Github repo.

Global Position Strategy

This would be a global positioning strategy. The overlay you are creating would be positioned directly on the screen, not in relation to an element. This is good for a dialog popup or modal window.

  overlayConfig = this.overlay.position().global()
    .centerHorizontally().centerVertically();

Flexible Connected To Strategy

This is what you want to use for Toolbars, menu, things that pop out of a button. You'll have to pass in a reference to your button you want the overlay to be connected to:

<button id="toolbar-icons" cdkOverlayOrigin mat-button class="toolbar-button" (click)="this.showAppContext()">

and in your Component.ts

showAppContext() {
  const appOverlayRef: AppOverlayRef = 
    this.appOverlayService.open(this.origin);
}

ConnectionPositionPair - this is a list of preferred positions, from most to least desirable. So it will first try to use the first position you pass in.

originX: This will be 'start', 'end', or 'center'. It is the attachment point for your overlay. If you have passed in a button to your .flexibleConnectedTo function, this refers to the start, end and center of that element.

originY: this will be 'top', 'bottom' or 'center'. This refers to the top, bottom or center of the element passed in.

So { originX: 'start', originY: 'bottom' } would be the bottom left hand corner of the button.

overlayX and overlayY have the same options, but refer to the where the overlay will be attached to. { overlayX: 'start', overlayY: 'top' } is attaching the upper left hand corner of the overlay to the origin we have specified.

Then, as you can see in the array, we can pass multiple positions in. If the overlay doesn't fit in the first position, it will try the next position in the array. So, if the overlay doesn't fit on the screen the first way, it will automatically shift to the second position, which is defined here as connecting the upper-left hand of the bottom to the bottom left hand of the overlay.

const positions = [
  new ConnectionPositionPair(
   { originX: 'start', originY: 'bottom' },
   { overlayX: 'start', overlayY: 'top' }),
  new ConnectionPositionPair(
  { originX: 'start', originY: 'top' },
  { overlayX: 'start', overlayY: 'bottom' })];
];

withPush

You can set withPush to true, which will push the overlay on-screen if none of the provided positions fit.

The code is still the best place to see the documentation: https://github.com/angular/material2/blob/master/src/cdk/overlay/position/connected-position.ts


David Rinck's answer to this question helped me after days and days of trial and error, so I thought I'd post the cheat sheet I put together based on that in the hope that it might help someone in the future.

This might not work for everybody, but it helped me:

// top-left
originX: 'start', // left corner of the button
originY: 'bottom', // bottom corner of the button
overlayX: 'start', // left corner of the overlay to the origin
overlayY: 'top', // top corner of the overlay to the origin

// top-right
originX: 'end', // right corner of the button
originY: 'bottom', // bottom corner of the button
overlayX: 'end', // right corner of the overlay to the origin
overlayY: 'top', // top corner of the overlay to the origin

// bottom-left
originX: 'start', // left corner of the button
originY: 'top', // top corner of the button
overlayX: 'start', // left corner of the overlay to the origin
overlayY: 'bottom', // top corner of the overlay to the origin

// bottom-right
originX: 'end', // right corner of the button
originY: 'top', // top corner of the button
overlayX: 'end', // right corner of the overlay to the origin
overlayY: 'bottom', // top corner of the overlay to the origin