0
0

More than 3 years have passed since last update.

Angularでのrxjsを用いたモーダル共通化

Last updated at Posted at 2021-09-02

はじめに

Angularに標準で入っているrxjsライブラリを使用してモーダルを共通化することができます!
一つだけモーダルを作っておき、あとはメソッドを呼び出して表示したいタイトル、内容を引数に渡すだけです!
最終的な成果物は動画↓のようになります
rxjsモーダル.gif

1. モーダルの状態を司るサービスの作成

src/app/services/modal.service.ts
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs';

@Injectable({
  providedIn: 'root',
})
export class ModalService {
  private _subject: Subject<{ title: string; body: string } | null> =
    new Subject();
  constructor() {}

  get subject() {
    return this._subject;
  }

  openModal(title: string, body: string) {
    this._subject.next({ title, body });
  }

  closeModal() {
    this._subject.next(null);
  }
}

2. モーダルコンポーネントの作成

src/app/components/modal.component.html
<div *ngIf="active" class="grayout">
  <main>
    <header>{{ title }}</header>
    <section>{{ body }}</section>
    <footer>
      <button (click)="closeModal()">OK</button>
    </footer>
  </main>
</div>
components/modal.component.scss
.grayout {
  position: fixed;
  top: 0;
  left: 0;
  background-color: #00000050;
  width: 100vw;
  height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  main {
    width: 500px;
    height: 500px;
    background-color: #ffffff;
    border-radius: 4px;
    display: flex;
    flex-direction: column;
    header {
      text-align: center;
      margin: 0;
      border-radius: 4px 4px 0 0;
      color: #ffffff;
      background-color: #1976d2;
      height: 40px;
      line-height: 40px;
    }
    section {
      flex: 1;
      padding: 15px;
    }
    footer {
      height: 40px;
      display: flex;
      padding: 15px;
      button {
        margin-left: auto;
      }
    }
  }
}
src/app/components/modal.component.ts
import { Component, OnInit, OnDestroy } from '@angular/core';
import { ModalService } from 'src/app/services/modal.service';
import { Subscription } from 'rxjs';

@Component({
  selector: 'app-modal',
  templateUrl: './modal.component.html',
  styleUrls: ['./modal.component.scss'],
})
export class ModalComponent implements OnInit, OnDestroy {
  active = false; // モーダルの表示、非表示を切り替える変数
  title = '';
  body = '';
  subscription: Subscription;

  constructor(private modalService: ModalService) {
    // subscribeで購読し、タイトル&内容が流れてきた時はモーダルを表示。空の場合は非表示
    this.subscription = this.modalService.subject.subscribe((next) => {
      if (next) {
        this.active = true;
        this.title = next.title;
        this.body = next.body;
      } else {
        this.active = false;
        this.title = '';
        this.body = '';
      }
    });
  }

  ngOnInit(): void {}

  ngOnDestroy(): void {
    this.subscription.unsubscribe();
  }

  closeModal() {
    this.modalService.closeModal();
  }
}

3. モーダル呼び出し側の作成

src/app/pages/about.component.html
<button (click)="openModal1()">モーダルを開く1</button>
<button (click)="openModal2()">モーダルを開く2</button>
<button (click)="openModal3()">モーダルを開く3</button>
src/app/pages/about.component.ts
import { Component, OnInit } from '@angular/core';
import { ModalService } from 'src/app/services/modal.service';

@Component({
  selector: 'app-about',
  templateUrl: './about.component.html',
  styleUrls: ['./about.component.scss'],
})
export class AboutComponent implements OnInit {
  constructor(private modalService: ModalService) {}

  ngOnInit(): void {}

  // モーダルを表示したい場合はモダールサービスのopenModalメソッドを呼び出すだけ!
  openModal1() {
    this.modalService.openModal('タイトル1', '内容1');
  }
  openModal2() {
    this.modalService.openModal('タイトル2', '内容2');
  }
  openModal3() {
    this.modalService.openModal('タイトル3', '内容3');
  }
}

0
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
0
0