Angular CDK Overlayで画面の絶対位置を指定してオーバーレイを表示する
久しぶりにブログ書いています。どうにも仕事が忙しいと書く気力が出ません。
今回は Angular CDK Overlay を使用してサクッとオーバーレイを表示してみます。オーバーレイは画面の任意の場所に Component を表示することができます。 Angular Material だと Dialog や Select などに使用されています。
Angular CDK Overlay には Global と Connected の2種類の位置設定があります。前者は画面上の絶対位置でオーバーレイを表示し、後者は特定の要素に対して相対位置で表示します。この記事では前者の Global を扱います。
環境
Angular CLI: 9.1.3 Node: 12.16.2 OS: win32 x64 Angular: 9.1.3 ... animations, cli, common, compiler, compiler-cli, core, forms ... language-service, platform-browser, platform-browser-dynamic ... router Ivy Workspace: Yes Package Version ----------------------------------------------------------- @angular-devkit/architect 0.901.3 @angular-devkit/build-angular 0.901.3 @angular-devkit/build-optimizer 0.901.3 @angular-devkit/build-webpack 0.901.3 @angular-devkit/core 9.1.3 @angular-devkit/schematics 9.1.3 @angular/cdk 9.2.1 @angular/material 9.2.1 @ngtools/webpack 9.1.3 @schematics/angular 9.1.3 @schematics/update 0.901.3 rxjs 6.5.5 typescript 3.8.3 webpack 4.42.0
今回のコードは こちら に Push しています。
オーバーレイで Component を表示する
まずは Angular CDK Overlay を使用して単純に Component を表示してみます。ここで表示する Component は OverlayContentComponent
とします。
シンプルに表示する
まずは app.module.ts
に OverlayModule
を追加します。意外と忘れがちです。
次に app.component.ts
のコンストラクターで Overlay
をインポートし、 showOverlay
メソッドを追加してオーバーレイを表示します。ただオーバーレイをただ表示するだけであれば次の3手順だけで表示できます。
Overlay#create(OverlayConfig)
でオーバーレイに対する参照を取得する- 表示する Component に対する
ComponentPortal
を作成する - OverlayRef に ComponentPortal をアタッチする
import type { OverlayConfig, OverlayRef } from '@angular/cdk/overlay'; import { Overlay } from '@angular/cdk/overlay'; import { ComponentPortal } from '@angular/cdk/portal'; import type { ComponentRef } from '@angular/core'; import { Component } from '@angular/core'; import { OverlayContentComponent } from './overlay-content/overlay-content.component'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.scss'], }) export class AppComponent { constructor( private readonly _overlay: Overlay, ) { } showOverlay() { const config: OverlayConfig = { width: 'auto', height: 'auto', }; const overlayRef: OverlayRef = this._overlay.create(config); const componentPortal: ComponentPortal<OverlayContentComponent> = new ComponentPortal(OverlayContentComponent); const componentRef: ComponentRef<OverlayContentComponent> = overlayRef.attach(componentPortal); } }
このコードを実行すると DOM ツリーとは異なる位置に OverlayContent Component が表示されていることが確認出来ます。
オーバーレイを閉じる
オーバーレイは表示したままだととても邪魔になりますので、表示を消すことも必要です。オーバーレイを削除するには OverlayRef#detach
または OverlayRef#dispose
を呼び出します。前者は表示されている Component が削除されますが OverlayRef の再利用ができます。後者は OverlayRef 自体の再利用すらできなくなります。あまり OverlayRef を再利用するパターンは無いと思いますので dispose を呼び出しておけば良いです。
<!-- app.component.html --> <button (click)="showOverlay()">Show overlay</button> <button (click)="closeOverlay()">Close overlay</button>
// app.component.ts import type { OverlayConfig, OverlayRef } from '@angular/cdk/overlay'; import { Overlay } from '@angular/cdk/overlay'; import { ComponentPortal } from '@angular/cdk/portal'; import type { ComponentRef } from '@angular/core'; import { Component } from '@angular/core'; import { OverlayContentComponent } from './overlay-content/overlay-content.component'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.scss'], }) export class AppComponent { private _overlayRef?: OverlayRef; constructor( private readonly _overlay: Overlay, ) { } showOverlay() { const config: OverlayConfig = { width: 'auto', height: 'auto', }; const overlayRef: OverlayRef = this._overlayRef = this._overlay.create(config); const componentPortal: ComponentPortal<OverlayContentComponent> = new ComponentPortal(OverlayContentComponent); const componentRef: ComponentRef<OverlayContentComponent> = overlayRef.attach(componentPortal); } closeOverlay() { this._overlayRef?.dispose(); this._overlayRef = undefined; } }
GlobalPositionStrategy で画面の任意の位置に表示する
次に PositionStrategy
を使用して、表示するオーバーレイの位置を調整します。 PositionStrategy
は Overlay 表示時の位置を決定するためのインターフェースです。 CDK ではこの記事の最初にも述べた通り画面上の絶対位置を指定する GlobalPositionStrategy
、要素に対する相対位置を指定する FlexibleConnectedPositionStrategy
の2つが実装されています。もちろんただのインターフェースですので、自分で実装するのも OK です。
この記事では GlobalPositionStrategy
を取り扱います。 GlobalPositionStrategy は画面の絶対位置を指定するものなので表示オプションもシンプルで、画面中央に表示する centerVertical/Horizontal
や 絶対位置を指定する left/right/top/bottom
を使用して位置を決定します。
取得するには Overlay#position#global
を呼び出し、例えば画面中央に表示するには以下のように centerVertical
と centerHorizontal
をチェインします。
showOverlay() { let positionStrategy: GlobalPositionStrategy = this._overlay.position().global(); positionStrategy = positionStrategy.centerVertically().centerHorizontally(); const config: OverlayConfig = { positionStrategy, width: 'auto', height: 'auto', }; const overlayRef: OverlayRef = this._overlay.create(config); const componentPortal: ComponentPortal<OverlayContentComponent> = new ComponentPortal(OverlayContentComponent); const componentRef: ComponentRef<OverlayContentComponent> = overlayRef.attach(componentPortal); }
left: 10px; bottom: 10px
を指定すると左下に表示されます。