본문 바로가기

프론트엔드/앵귤러

앵귤러 모달

반응형

웹프로그로밍에서 모달은 팝업이나 dialog를 의미합니다. Vanilla JavaScript (framework 사용 없이 HTML, CSS, JS만으로 만들어진 어플케이션)를 사용하여 모달을 만드는 것도 가능하지만 앵귤러에서 제공하는 기능들을 활용하면 모달의 재사용성을 높이고 정보를 공유를 보다 손쉽게 할 수 있습니다. 앵귤러를 사용하여 모달을 구현하는 방법을 살펴보겠습니다.


먼저 모달 구현을 위해 사용할 기능들을 살펴볼까요?
1. 모달 Component (모달 닫기 등 공통된 기능과 layout 제공)
2. 모달 Service (모달의 상태를 관리하고 공유하는 기능 제공)
3. 개별 모달 Component (로그인 등 특정된 내용을 제공하고 기능 수행)

구현된 코드는 아래와 같습니다

공통 모달 Component

공통모달은 모달의 공통된 기능을 과 레이아웃을 제공하는 컴포넌트로

// modal.component.ts

import { Component, Input, OnInit } from '@angular/core';
import { ModalService } from 'src/app/services/modal.service';

@Component({
  selector: 'app-modal',
  templateUrl: './modal.component.html',
  styleUrls: ['./modal.component.css'],
})
export class ModalComponent implements OnInit {  
  @Input() modalId = ''
  constructor(public modalService: ModalService) {}

  ngOnInit(): void {}
}

아래와 같이 모달 서비스로 부터 전송받은 모달의 상태에 따라 아래와 같이 모달을 표시하거나 사라지게 하는 역할, 전체 스타일 적용 등을 수행합니다. 이는 공통으로 적용되는 코드를 하나의 컴포넌트에서 구현하여 같은 작업의 반복 필요성을 제거해 줍니다.

<!-- modal.component.html -->

<div class="container" [ngStyle]="{display:modalService.getIsOpen(modalId) ? '' : 'none'}">
  <div class="box" style="width: 500px; height: 400px; background-color: antiquewhite; z-index: 2;">
    <ng-content select="[heading]"></ng-content>    
    <button (click)="modalService.closeModal('auth')">Close</button>
    <ng-content></ng-content>
  </div>
  <div (click)="modalService.closeModal(modalId)" class="shade"></div>
</div>

모달 Service

모달의 생성, 수정, 삭제 등 모달을 관리하고 모달을 사용하는 각 콤포넌트에 모달의 정보를 전달합니다.

// modalService.ts

import { Injectable } from '@angular/core';
import { Modal } from '../models/modal';
@Injectable({ providedIn: 'root' })
export class ModalService {
  modals: Modal[] = []; // holds all the modals registered
  constructor() {}

  // 모달의 오픈 상태변경
  closeModal(id:string) {    
    const modal = this.modals.find(m => m.id === id);
    if(modal) {
      modal.isOpen = !modal.isOpen;
    }
  }

  // 주어진 매개변수와 일치하는 모달을 오픈상태로 반환
  getIsOpen(id:string) : boolean {
    return !!this.modals.find(m => m.id === id)?.isOpen;
  }

  // 새로운 모달을 모달 배열에 추가
  register(id: string) {
    this.modals.push({
      id: id,
      isOpen: false,
    });
  }
  
  // 아이디가 일치하는 모달을 모달 배열에서 제외
  unRegister(id:string) {
  	this.modals = this.modals.filter(m => m.id !== id)
  }
}

모달 Model

모달이 가지는 속성을 정하는 인터페이스로 각 모달이 개별적으로 작동 가능하도록 가져야 하는 고유 아이디와 모달의 상태(열림, 닫힘)를 특정합니다.

// modal.ts

export interface Modal {
  id: string,
  isOpen: boolean,
}


개별 모달 Component

개별 모달은 각 모달이 수행하여야 할 기능을 포함하는 모달입니다. 예를들어, 회원가입이나 로그인 등 사용자 인증과 관련된 부분을 하나의 개별 모달로 생성합니다.

// auth-modal.component.ts

import { Component, OnInit } from '@angular/core';
import { ModalService } from 'src/app/services/modal.service';

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

  // 모달생성
  ngOnInit(): void {
    this.modalService.register('auth')
  }
  
  // 컴포넌트가 소멸될 때 모달제거
  ngOnDestroy:void {
    this.modalService.unRegister('auth')
  }
}
<!-- auth-modal.component.html -->

<app-modal [modalId]="'auth'">
  <p heading>title</p>

  <ul style="display: flex; list-style: none; align-items: center; justify-content: space-around;">
    <li>Login</li>
    <li>Join</li>
  </ul>

  <form action="" style="width: 100%; text-align: center;">
    <label for="">login</label>
    <div>
      <input type="text">
      <input type="text">
    </div>
  </form>

  <form action="" style="width: 100%; text-align: center;">
    <label for="">join</label>
    <div>
      <input type="text">
      <input type="text"><input type="text">
      <input type="text">
    </div>
  </form>
</app-modal>

앞서 설정한 모달의 아이디는 여러개의 모달이 한 번에 열리는 오류를 방지해 줍니다. 예로, 아래처럼 추가된 모달은 따로 설정을 하지 않으면 모달의 상태가 오픈이 될 때 모두 한 번에 표시되는데요. 아이디를 추가하고 이를 서비스에서 해당 아이디를 찾아서 상태를 변경하는 방식으로 구현 시 이러한 오류를 방지할 수 있습니다.

<!-- auth-modal.component.html -->

<app-modal [modalId]="'auth'">
  <p heading>title</p>

  <ul style="display: flex; list-style: none; align-items: center; justify-content: space-around;">
    <li>Login</li>
    <li>Join</li>
  </ul>

  <form action="" style="width: 100%; text-align: center;">
    <label for="">login</label>
    <div>
      <input type="text">
      <input type="text">
    </div>
  </form>

  <form action="" style="width: 100%; text-align: center;">
    <label for="">join</label>
    <div>
      <input type="text">
      <input type="text"><input type="text">
      <input type="text">
    </div>
  </form>
</app-modal>

<!-- additional -->
<app-modal [modalId]="'test'">
  dummy
</app-modal>

이상으로 앵귤러에서 모달을 만드는 방법을 살펴보았습니다.

 

728x90
반응형