Angularでmodalなダイアログを表示する



今回はこちらのサイトを参考にしてモーダルなダイアログを表示してみた。
https://medium.com/swlh/how-to-create-a-modal-dialog-component-in-angular-8-88028d909be0

## 環境

- Angular： v9.0.4
- Node： v12.16.1
- OS： win32 x64

## 準備

### MatDialogとMatButtonを使用するためAngularMaterialを追加する

```Console
ng add @angular/material
```

色々きかれるが、Enterキーを押してデフォルト値で設定した。  

### component生成

```Console
ng generate component modal
```

app-modalというcomponentが生成される。  

## コード記述

まずは追加したAngularMaterialを使えるようにapp.module.tsにコードを記述する。  

```Typescript:app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { ModalComponent } from './modal/modal.component';

import { MatButtonModule } from '@angular/material/button'; // 追加
import { MatDialogModule } from '@angular/material/dialog'; // 追加

@NgModule({
  declarations: [
    AppComponent,
    ModalComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    BrowserAnimationsModule,
    MatButtonModule, // 追加
    MatDialogModule // 追加
  ],
  providers: [],
  bootstrap: [AppComponent],
  entryComponents: [ModalComponent] // 追加
})
export class AppModule { }

```

styles.cssでグローバルスタイルを設定する。
参考サイトのまま設定させて頂きました。

```css:styles.css
html, body {
    height: 100%;
}

body {
    margin: 0;
    font-family: Arial, Helvetica, sans-serif;
    display: grid;
    justify-items: center;
    align-items: center;
    background-color: #3a3a3a;
}

/* Overwrite the styles of the mat-dialog-container element globally, but only for those
that have an id of `modal-component` */
/* https://stackoverflow.com/a/48689004/9263761 */
mat-dialog-container#modal-component {
    border: 3px solid #262626;
    border-radius: 11px;
    background-color: #1a1a1a;
}
```

### app.component

続いてapp.component.htmlを編集してボタンとクリックイベントを追加する。

```html:app.component.html
<main id="logout-button-holder">
    <button mat-raised-button id="logout-button" (click)="openModal()">ログアウト</button>
</main>
```

- mat-raised-button：MatButton。
- logout-button：cssと紐づける。
- openModal()：ボタンクリック時に呼び出されるメソッド。  

styles.cssとボタンがちゃんと反映されてるか確認。
> ng serve -o

ボタンのスタイルもいじってみる。

```css
#logout-button {
    color: white;
    background-color: #4b4b4b;
    border: 1px solid black;
}
```

app.component.tsにopenModal()メソッドを追加する。  
このメソッドでMatDialogを開くようにする。  

```typescript:app.component.ts
import { Component } from '@angular/core';

import { MatDialog, MatDialogConfig } from '@angular/material/dialog';
import { ModalComponent } from './modal/modal.component';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  constructor(public _matdialog: MatDialog) {}

  openModal() {
    const dialogConfig = new MatDialogConfig();

    // 表示するdialogの設定
    dialogConfig.disableClose = true;
    dialogConfig.id = "modal-component";
    dialogConfig.height = "350px";
    dialogConfig.width = "600px";

    const modalDialog = this._matdialog.open(ModalComponent, dialogConfig);
  }
}
```

import で ModalComponent と **MatDialog**, **MatDialogConfig** を記述する。  

- ModalComponent：はじめに生成したコンポーネント
- MatDialog：AngularMaterialライブラリ。主にダイアログの操作関連を担うクラス。  
- MatDialogConfig：ダイアログの設定をするクラス。
  - disableClose：true値にすることでユーザーがモーダルの外側をクリックしても閉じない。
  - id：cssなどと紐づけ。  
  - height：ダイアログの高さ
  - width：ダイアログの幅

_matdialog.open()でダイアログを開く。第一引数に開くコンポーネント、第二引数にダイアログの設定値を渡す。  

logoutボタンを押すことでmodalComponentが呼び出されているのが確認できる。  

これで今回の目的は達成した。  

## ダイアログ側の処理

ダイアログ側でも処理してみる。

```html:modal.component.html
<div id="modal-content-wrapper">
  <header id="modal-header">
      <h1 id="modal-title">ログアウト確認</h1>
  </header>
  <section id="modal-body">
      <p>ログアウトしてもよろしいでしょうか？</p>
  </section>
  <footer id="modal-footer">
      <button mat-raised-button id="modal-action-button" (click)="actionFunction()">ログアウト</button>
      <button mat-raised-button id="modal-cancel-button" (click)="closeModal()">戻る</button>
  </footer>
</div>
```

戻るとログアウトボタンを追加。
modal.componentのcssもいじってみる。

```css:modal.component.css
#modal-content-wrapper {
  width: 100%;
  height: 100%;
  display: grid;
  grid-template-rows: repeat(1fr, 3);
  color: white;
}

#modal-title {
  font-size: 22px;
}

#modal-footer {
  justify-self: right;
  align-self: center;
}

#modal-action-button {
  color: white;
  margin-right: 30px;
  background-color:#3b3b3b;
}

#modal-cancel-button {
  color: white;
  background-color: #4e4e4e;
}
```

続いて、ボタンのクリックイベント時に呼び出される関数を**Typescript**側に記述する。

```Typescript:modal.component.ts
import { Component, OnInit } from '@angular/core';

import { MatDialogRef } from '@angular/material/dialog';  // 追加

@Component({
  selector: 'app-modal',
  templateUrl: './modal.component.html',
  styleUrls: ['./modal.component.css']
})
export class ModalComponent implements OnInit {

  constructor(public _dialogRef: MatDialogRef<ModalComponent>) { }

  ngOnInit(): void {
  }

  // logoutボタンクリックイベントで呼び出される関数
  actionFunction() {
    alert("You have logged out.");
    this.closeModal();
  }

  // ダイアログを閉じる
  closeModal() {
    this._dialogRef.close();
  }

}
```

- MatDiarogRef：現在開いてるダイアログにアクセスする
- actionFunction()：ログアウト処理をする関数（今回はalertでメッセージを出している）
- closeModal()：現在開いてるダイアログを閉じる関数