Search code examples
angularoverlayangular-cdk

Angular CDK Overlay: how to calculate projected content height/width


I'm using Angular CDK Overlay. One of the properties in config is FlexibleConnectedPositionStrategy. Im trying to attach overlay on top of my click trigger. All is working fine when there is enough space on top to fit overlay. What Id like to do is check if there is not enough space at the top then attach overlay to the bottom of the trigger. To do that I need some way after calling Overlay.open(...) to get access to projected content so i can calculate it's dimensions. Is there way to do that?

So far I only see hackish way to access internal _projectedViews[] array but its undocumented feature. Trying to find cleaner way.


Solution

  • Andrei, when you define the cdk-overly you choose the "positionStrategy". The order of the positions is defined in the array withPositions. You can see this link (I don't know if is a bit outdated or not): netanet basal cdk overlay (really the Angular material cdk-overlay is very poor), that I try to simply in this SO

    Normally you import the overlay and the overlayPositionBuilder

    constructor(public overlay: Overlay)
    

    You create the overLayRef using create

    const overlayRef = overlay.create();
    

    The function create is an object of type OverlayConfig with properties: Height, width, maxWidth,.. and (among others) positionStrategy, that is an object of type PositionStrategy

    So first you create an object of type PositionStrategy. For this you can use the the method position() of overlay

    This object has the method flexibleConnectedTo

    You can choose "connected" to ElementRef | HTMLElement| Point & { width?: number; height?: number;};

    this return a FlexibleConnectedPositionStrategy that you can give value to positions (an array of ConnectionPositionPair), or directy or using the method withPositions

    so, e.g.

    const positionStrategy = this.overlayPositionBuilder
          .flexibleConnectedTo({ x, y })
          .withPositions([{
            originX: 'center',
            originY: 'top',
            overlayX: 'center',
            overlayY: 'bottom',
          },
          {
            originX: 'center',
            originY: 'bottom',
            overlayX: 'center',
            overlayY: 'top',
          }]);
    

    make that try first attach to top, but if there're no enough space use the second defined position

    Update

    Well, de final position can be get enclosed in a setTimeout() after execute the attach, e.g.

       //After attach
       this.overlayRef.attach(new TemplatePortal(menu, viewContainerRef, {
                $implicit: data, close:this.close
            }));
        //enclosed in a setTimeout() we has this.overlayRef.overlayElement
        setTimeout(()=>{
          console.log(this.overlayRef.overlayElement.getBoundingClientRect())
        })