Why use overlays?

An Overlay is a Material Design Component for Angular that covers popup dynamic content. It is powerful and easy to use, especially when developing your own component library. You can use an Overlay for almost any scene that pops up content. We already use overlays in our own component library, such as custom Select, Cascader, Tree Select, Tooltip, Dialog, etc.

  1. Let the user no longer carry on the tedious location calculation, but simply through the configuration of parameters to achieve the location of the content, and about the location of various situations have been taken into account.
  2. Component pop-ups are implemented using overlays to avoid incompatibilities in each implementation, such as mutual overwriting.

Simple example – link pop-up location source

The following example shows the use of overlays. This popup scenario is similar to a Tooltip. The popup Overlay content is based on a referenced location source origin element.

Install and import modules

If the CDK is not installed in the project, install it first

  npm install @angular/cdk
Copy the code
Import OverlayModule
import {OverlayModule} from '@angular/cdk/overlay';

@NgModule({
  imports: [
    OverlayModule,
    // ...
  ]
})
export class AppModule {
}
Copy the code
Sample template content
<div class="demo-trigger"> <! --> <button mate-raised -button cdkOverlayOrigintype="button"
      [disabled]="overlayRef"
      (click)="openWithConfig()">Open</button> </div> <! -- Pop up dynamic content template --> <ng-template#overlay>
  <div class="demo-overlay">
    <div style="overflow: auto;">
      <ul><li *ngFor="let item of itemArray; index as i">{{itemText}} {{i}}</li></ul>
    </div>
  </div>
</ng-template>
Copy the code

In addition to the pop-up template, there is also an Open button in the template above, which will be used later as the origin location source

Injecting Overlay service

Inject the Overlay service in the component’s constructor constructor, and the following code includes the component’s definition

@Component({
  selector: 'overlay-demo',
  templateUrl: 'connected-overlay-demo.html'
})
export class ConnectedOverlayDemo {
  @ViewChild(CdkOverlayOrigin, {static: false}) _overlayOrigin: CdkOverlayOrigin;
  @ViewChild('overlay', {static: false}) overlayTemplate: TemplateRef<any>; Constructor (public Overlay: Overlay) {}openWithConfig() {}}Copy the code

To handle the injection service, the above code also retrieves two objects from the template via ViewChild, which will be explained later when needed.

Building a location strategy

First create a location strategy, used here is FlexibleConnectedPositionStrategy strategy, look at the code

const positionStrategy = this.overlay.position() .flexibleConnectedTo(this._overlayOrigin.elementRef) .withPositions([ {  originX:'start',
          originY: 'bottom',
          overlayX: 'start',
          overlayY: 'top',}]);Copy the code

Create methods flexibleConnectedTo FlexibleConnectedPositionStrategy strategy must provide a location source parameter, used here is enclosing _overlayOrigin. ElementRef, The location of the popup content is based on the location source, this._overlayOrigin is actually the Open button in the template fetched via ViewChild.

Call create method
OverlayRef = this.overlay. Create ({overlay Strategy, // scrollStrategy: This. Overlay. ScrollStrategies. Reposition (), / / rolling strategy direction: this. Dir. Value, / / usability Settings, need not too concerned about minWidth: 200, / / the minimum width of the overlay layer minHeight: the minimum height of the 50 / / overlay layer hasBackdrop:false// whether to display mask layer});Copy the code

The OverlayRef method generates an OverlayRef object of type OverlayRef, which is used to manage the overlays.

Attach templates via overlayRef

Once everything is ready, you need to tell the Overlay pop-up layer what to display, pop the template directly, define it in the template, and use the Attach method of the overlayRef. The code is as follows

 this.overlayRef.attach(new TemplatePortal(this.overlayTemplate, this.viewContainerRef));
Copy the code

The code uses this.overlayTemplate, the template definition that displays the popup content fetched from ViewChild.

Note: The attach method uses Protals in CDK. The parameter type that attach method receives is actually TemplatePortal, because this is essentially creating components dynamically. In addition, it also supports ComponentPortal of component type. The article zhuanlan.zhihu.com/p/59719621 about Portals can be reference in front of me

Through the above simple steps to achieve dynamic content pop-up, the effect picture is shown below

Simple example – Global pop-up

In a completely different way, now I’m going to use Overlay to pop content directly onto the window without linking to any location sources. It’s very easy to just change the location policy and look at the code for the new location policy that you’re using

 const positionStrategy = this.overlay.position()
      .global()
      .height('300px')
      .centerHorizontally()
      .top('70px');
Copy the code

Calling global() returns the global position Strategy, a position strategy based on the absolute positioning of the browser window. The above code is centered horizontally, 70px from the top

Overlay Location Strategy

Overlay provides three methods corresponding to three position strategies through the OverlayPositionBuilder service. The OverlayPositionBuilder is injected into the Overlay service through the constructor. This.overlay.position() returns an object of type OverlayPositionBuilder

ConnectedPositionStrategy – link point location strategy

Note: this policy is deprecated, use FlexibleConnectedPositionStrategy strategy instead of, but the discussion can continue here, for showing the position of connection relationship

ConnectedTo method returns ConnectedPositionStrategy strategy as an example, the strategy implementation is based on an operation on the source position to the position of the popup layer Overlay the location of the connection relationship strategy, create the policy code is as follows

  connectedTo(
      elementRef: ElementRef,
      originPos: OriginConnectionPosition,
      overlayPos: OverlayConnectionPosition): ConnectedPositionStrategy {
    return new ConnectedPositionStrategy(
        originPos, overlayPos, elementRef, this._viewportRuler, this._document, this._platform,
        this._overlayContainer);
  }
Copy the code

The parameters are:

  1. ElementRef Specifies the element to connect to, usually the one that triggers the pop-up
  2. OriginPos The position point of the connection element
  3. OverlayPos Overlay location point

Use diagrams to show the position relationships it maintains

The combination of position points shown above is just one case (lower left point – upper left point) and the position configuration code is shown below

 {
  "originX": "start"."originY": "bottom"."overlayX": "start"."overlayY": "top"
}
Copy the code

Enumerable values in the x direction are defined as follows

 export type HorizontalConnectionPos = 'start' | 'center' | 'end';
Copy the code

Enumerable value definitions in the y direction

 export type VerticalConnectionPos = 'top' | 'center' | 'bottom';
Copy the code

Various combinations of locations can be implemented based on the above enumerated values.

FlexibleConnectedPositionStrategy – flexible connection point location strategy

Note: the source code now ConnectedPositionStrategy also through correlation FlexibleConnectedPositionStrategy strategy implementation strategy finally, so recommend direct use of the policy

Through flexibleConnectedTo method returns FlexibleConnectedPositionStrategy strategy as an example, this is the most complicated one Overlay location strategy, Flexible on can say so, This strategy is used when using Overlay instructions. It has more control over the position strategy and features the following:

  1. withDefaultOffsetX,withDefaultOffsetYSets the offset relative to the base position.
  2. withPositionsAn array of parameters of type ConnectionPositionPair that provides multiple position combinations. When the pop-up content of one position combination is outside the window, the corresponding position combination is applied to prevent the content from being invisible.
  3. withFlexibleDimensionsControls whether the width and height of the Overlay popup layer are limited within the browser window. When set to true, the width and height are adaptive to the browser boundaries, displaying the content as scroll bars.
  4. And other predictable details about the location

The code to create the policy is as follows

   /**
   * Creates a flexible position strategy.
   * @param origin Origin relative to which to position the overlay.
   */
  flexibleConnectedTo(origin: FlexibleConnectedPositionStrategyOrigin):
    FlexibleConnectedPositionStrategy {
    return new FlexibleConnectedPositionStrategy(origin, this._viewportRuler, this._document,
        this._platform, this._overlayContainer);
  }
Copy the code

There is only one origin argument that provides a reference to the positional source element to be linked.

GlobalPositionStrategy

Global location policy. The global method returns an instance of the GlobalPositionStrategy policy with no arguments. The code for creating the policy is as follows

  /**
   * Creates a global position strategy.
   */
  global(): GlobalPositionStrategy {
    return new GlobalPositionStrategy();
  }
Copy the code

GlobalPositionStrategy provides various methods for global positioning and can be invoked in a chained manner, as shown in the following code

const strategy = this.overlay
  .position()
  .global()
  .width('500px')
  .height('100px')
  .centerHorizontally()
  .centerVertically();
Copy the code

The top, left, bottom, and right methods provide absolute positioning for each orientation. The parameter is the offset at that orientation. For example, the offset at the top of 10px is ’10px’, and this is the offset that breaks the horizontal or vertical center.

PositionStrategy Location policy interface

The location policy interface is defined as follows

 import {OverlayReference} from '.. /overlay-reference';

/** Strategy for setting the position on an overlay. */
export/** attach(overlay: OverlayReference): void; /** attach(overlay: OverlayReference): void; /** Update overlay element position. */ apply(): void; /** Call */ detach when overlay calls detach? (): void; /** Cleans up any DOM modifications made by the position strategy,if necessary. */
  dispose(): void;
}
Copy the code

Interfaces define the method signatures that a location policy must contain, a common form of abstraction in object-oriented programming. OverlayRef only relies on the PositionStrategy interface, not on the implementation of a specific strategy. When creating OverlayRef, you need to provide an instance of a specific location strategy (usually configured when creating Overlay). If necessary, you can also implement your own location strategy. Implementing your own location policy simply implements the interface and defines a concrete implementation of the interface signature. In line with the three characteristics of object-oriented encapsulation, inheritance, polymorphism, in line with the five principles of single responsibility principle, open and closed principle, this abstract idea is worth learning

The rolling strategy

Overlay provides the global service ScrollStrategyOptions, which provides a strategy for dealing with Overlay rolling.

NoopScrollStrategy – does not provide any processing

While scrolling does nothing, call the noop method of scrollStrategies

  noop = () => new NoopScrollStrategy();
Copy the code
CloseScrollStrategy – Turns off the scrolling strategy

Once the user has scrolling behavior, immediately close the overlay overlay overlay overlay layer and call the close method of scrollStrategies

close = (config? : CloseScrollStrategyConfig) => new CloseScrollStrategy(this._scrollDispatcher, this._ngZone, this._viewportRuler, config)Copy the code

You can configure the parameter threshold in config to set the critical point of a rolling pixel. Overlay will be turned off only when the rolling distance is greater than this parameter.

BlockScrollStrategy – Blocks rolling strategy

This policy blocks page-level scrolling by calling the block method of scrollStrategies

   block = () => new BlockScrollStrategy(this._viewportRuler, this._document);
Copy the code

Prevent page-level scrolling by adding a style cdK-global-ScrollBlock to the HTML tag of the page, as defined below

position: fixed;
width: 100%;
overflow-y: scroll;
Copy the code

RepositionScrollStrategy – Reposition the rollstrategy

Once the user has a scrolling behavior, the strategy will update the position of the pop-up layer according to the scrolling position, the effect is that the pop-up layer will follow the scrolling and the position of the position source remains unchanged, and the reposition method of scrollStrategies is called

reposition = (config? : RepositionScrollStrategyConfig) => new RepositionScrollStrategy( this._scrollDispatcher, this._viewportRuler, this._ngZone, config)Copy the code

You can configure two parameters: scrollThrottle, which controls the jitter rate when rolling events trigger reupdates, and autoClose, which specifies whether to disable overlay overlay overlay when rolling events occur.

Scroll trigger

In this case, CDK provides a scrolling service (in the CDK /scrolling directory). ScrollDispatcher, a trigger that processes global scrolling events, is used. Closing the rolling policy and repositioning the rolling policy are both flows returned by subscribing to the SCrolled method of ScrollDispatcher (collectively called SCrolled flows later). There are several points to be made clear

  1. The scrolled global page document must trigger the SCrolled flow
  2. If the overlay shows Backdrop, it has an effect on the repositioning scrolling strategy. Showing Backdrop prevents scrolling of local elements on the page, but has no effect on scrolling of the document on the global page. So you can see that the official overlay example shows the Backdrop layer, Reposition still works, but it may fail to implement the overlay following the scroll itself, because local scroll events cannot be triggered at all.
  3. Scrolled flow is a global roll-listening, any element rolling associated with the injected CdkScrollable will trigger scrolled flow (if rolling is not related to overlay, recalculation of position will not affect, it will still be the original position after calculation, but this feeling needs to be optimized)
Implement rolling Overlay layer relocation of local elements

Because most domestic software fixes the whole window and then realizes overflow: Scroll through local element setting style, here is only the idea

  1. So if you want to close Overlay on Backdrop, if you click on Backdrop, then you have to do it yourself
  2. Constructing a CdkScrollable example from the scroll region allows code to iterate over the scrollable parent of the Origin element

So this is not easy to understand, it’s abstract, it’s a combination of overlay, Scroll, position strategy, scroll strategy, so now you can do it first, and then look at the source code if you need to know the details.

conclusion

In this article, we introduce the advantages of using overlays. In our component library, there are many components that use overlays. In this article, we introduce the position strategy and scroll strategy of overlays. There are a lot of things to say about Overlay, and the whole idea of encapsulation is worth learning. That’s all. If you have any suggestions or questions, please leave a comment. In addition, the sample in this article is basically a Demo for overlays in Material Design Components for Angular. You can clone the code yourself if necessary

Git clone github.com/angular/com… CD Components yarn install // If there is no YARN and you need to install yarn globally, the node version must be 10.x NPM run dev-app



Worktile’s website: Worktile.com

Author: Zhenxing Yang, Engineer, Worktile

This article was first published on Worktile’s official blog.