8
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AngularAdvent Calendar 2023

Day 8

Angular CDKのCdkDialogでダイアログを爆速実装

Last updated at Posted at 2023-12-07

これはAngular Advent Calendar 2023の8日目の記事です。

はじめに

今年の Angular は Signal や Control Flow など盛りだくさんでした。これらの新機能も気になるところですが、他の方が素晴らしい記事をどんどん上げてくださっているので、僕は今年も Angular CDK の布教活動に努めたいと思います。

今回はアプリケーションを作る上で欠かせないモーダルダイアログを CdkDialog を利用して実装していきます。

※ 先に完成したものも置いておきます。

ダイアログの表示

CdkDialogはダイアログで表示したいComponentさえ用意すれば後は数行で実装できるので早速やってみましょう。

ダイアログで表示したいコンポーネントを作成

@Component({
  selector: 'app-dialog',
  standalone: true,
  template: `
    <div style="background-color: white; padding: 24px;">
      <p>Dialog by CdkDialog</p>
    </div>
  `,
})
export class DialogComponent {}

CdkDialogの open() で呼び出す

import { DialogModule, Dialog } from '@angular/cdk/dialog';

@Component({
  selector: 'app-root',
  standalone: true,
  template: `
    <button (click)="openDialog()">Open Dialog</button>
  `,
  imports: [DialogModule],
})
export class App {
  private readonly dialog = inject(Dialog);

  openDialog() {
    this.dialog.open(DialogComponent);
  }
}

Dialog

たったこれだけで、シンプルなモーダルダイアログを実装出来ます。思ったよりずっと簡単ですよね。

見た目の共通化

CdkDialogでは、DialogConfigのcontainerオプションを利用することで共通の見た目を実装できます。

import { PortalModule } from '@angular/cdk/portal';

@Component({
  selector: 'app-dialog-container',
  standalone: true,
  template: `
    <div style="background-color: white; padding: 24px;">
      <ng-template cdkPortalOutlet></ng-template>
    </div>
  `,
  imports: [PortalModule],
})
export class DialogContainer extends CdkDialogContainer {}

上記のように CdkDialogContainer を継承したコンポーネントを作成したらcontainerオプションに指定するだけ。

openDialog() {
  this.dialog.open(DialogComponent, {
    container: DialogContainer
  });
}

これで全てのダイアログの見た目を共通化できます。

振る舞いの共通化

「ESCボタンを押したら閉じる」などダイアログに共通した振る舞いも DialogContainer に実装することで簡単に共通化できます。

import { DialogRef } from '@angular/cdk/dialog';
import { ESCAPE } from '@angular/cdk/keycodes';

export class DialogContainer extends CdkDialogContainer {
  private readonly dialogRef = inject(DialogRef);

  @HostListener('keydown', ['$event'])
  handleKeydown(event: KeyboardEvent) {
    const { keyCode } = event;
    if (keyCode === ESCAPE) {
      this.dialogRef.close();
    }
  }
}

※ DialogRefは自作ダイアログを実装する上でかなり便利なクラスですが、今回説明は省きます。もし気になる方は、公式ドキュメントを参照してください。

呼び出しの共通化

最後に呼び出し側のコードの冗長化を防ぐためにサービスを作成しましょう。

@Injectable({
  providedIn: 'root',
})
export class DialogService {
  private readonly dialog = inject(Dialog);

  open<C>(component: ComponentType<C>) {
    return this.dialog.open(component, {
      container: DialogContainer,
    });
  }
}
private readonly dialog = inject(DialogService);

openDialog() {
  this.dialog.open(DialogComponent);
}

これで呼び出しもスッキリし、細かい設定なども隠蔽することが出来ました。

まとめ

今回、改めてCdkDialogを使った共通化をやってみて、こんなだったっけ・・・?と自分で思うくらい簡単で驚いています。
Angular CDKの記事はまだまだ少なく、取っつきづらいイメージもあるかもしれませんが、今回のCdkDialogのように簡単で便利な機能がたくさんあります。

特にダイアログの共通化は比較的難易度の高い部類に入ると思うので、ぜひCdkDialogを使ってみてください。

明日は @scrpgil さんです!

8
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?