티스토리 뷰

Client Technologies/Angular

Angular : Modal 만들기

Korean Eagle 2020. 6. 14. 16:12
728x90

0. 이 포스트는 Modal 사용에 대한 semantic ui를 활용한 설명이다.

 

1. Modal은 자바스크립트 기반의 client 언어들이 가지는 공통적인 난제이다.

 

2. Modal은 브라우저 화면 전체를 불투명한 검정색으로 칠해 배경을 희미하게 처리하고 화면 중앙에 박스를 표출한다.

  2-1 이렇게 하려면 index.html 페이지의 body에 바로 붙어야 가능하다. 그렇지 않으면 상위레이어에 간섭을 받는다.

 

3. modal 컴포넌트를 생성하고 다음과 같이 설정한다.

  3-1 modal 컴포넌트 template ui

    3-1-1 modal이라는 컴포넌트를 만들었고 컴포넌트 template은 다음과 같다.

    3-1-2 위의 캡처 이미지의 내용이다. modal을 감싸는 검은 색 배경을 div로 작성한 것에 주의한다.

    3-1-3 코드를 보면 active class가 배경과 modal에 모두 설정되어 있는데, 둘다 화면에 표출한다는 의미다.

    3-1-4 모두 active 된 이유는 modal 컴포넌트를 무조건 표출하고 부모컴포넌트에서 표출여부를 관리하는 게 편하기 때문이다.

 

<div class="ui dimmer active">
  <div class="ui basic active modal">
    <div class="ui icon header">
      <i class="archive icon"></i>
      Archive Old Messages
    </div>
    <div class="content">
      <p>Your inbox is getting full, would you like us to enable automatic archiving of old messages?</p>
    </div>
    <div class="actions">
      <div class="ui red basic cancel inverted button">
        <i class="remove icon"></i>
        No
      </div>
      <div class="ui green ok inverted button">
        <i class="checkmark icon"></i>
        Yes
      </div>
    </div>
  </div>
</div>

 

  3-2 modal 컴포넌트 클래스

    3-2-1 이 객체를 부모컴포넌트에 붙이는 것이 아니라 최상위 body에 붙여야 한다.

    3-2-2 생성자에서 ElementRef를 주입받고 있는데 부모컴포넌트에서 설정한 app-modal 자신이라고 할 수 있다.    

      3-2-2-1 ngOnInit 메소드에서 초기화 할 때 브라우저 DOM에 바로 붙이는 코드를 작성한다.

      3-2-2-3 마찬가지로 객체가 사라질 때에도 DOM에서 제거해야 하기 때문에 ngOnDestroy 메소드를 작성하였다.

 

import { Component, OnInit, ElementRef } from '@angular/core';

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

  constructor(private element: ElementRef) { }

  ngOnInit(): void {
    document.body.appendChild(this.element.nativeElement)
  }

  ngOnDestroy() {
    this.element.nativeElement.remove()
  }
}

 

4. 이제 부모 클래스에서 이 modal을 사용하도록 작성한다.

  4-1 부모 template 코드

    4-1-1 template 파일에서 아래처럼 버튼을 만들어 버튼을 눌렀을 때 modal의 상태를 변경하도록 하였다.

    4-1-2 modal 상태 변수에 따라 modal 표출되도록 ngIf를 modal 컴포넌트에 사용하였다.

    4-1-3 나중에 사용자가 modal 닫기를 했을 때

      4-1-3-1 modal에서 보낸 close 이벤트 받아 modal을 보이지 않게 처리하는 이벤트 코드도 작성했다.

 

<app-title>
  Modal Component
</app-title>
<app-modal *ngIf="modalStatus" (close)="toggleModal()"></app-modal>
<div class="ui button" (click)="toggleModal()">Show Modal</div>

 

  4-2 부모 class 코드

    4-2-1 template에서 버튼을 누를 때마다 modalStatus가 true, false를 반복한다.

 

import { Component, OnInit } from '@angular/core';

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

  modalStatus = false

  constructor() { }

  ngOnInit(): void {
  }

  toggleModal() {
    this.modalStatus = !this.modalStatus
  }
}

 

5. 마지막으로 modal 컴포넌트가 부모와 소통할 수 있게 수정한다.

  5-1 modal 화면에서 배경을 클릭할 때, no, yes 버튼을 클릭할 때에 적절한 메소드가 호출하도록 수정한다.

  5-2 공통적으로 modal이 사라지는 작업이 필요한데

    5-2-1 부모 컴포넌트의 modal 상태 변수를 false로 변경하도록 close이벤트를 발생하여 처리한다. 5-3을 참고

 

<div class="ui dimmer active" (click)="closeModal()">
  <div class="ui basic active modal">
    <div class="ui icon header">
      <i class="archive icon"></i>
      Archive Old Messages
    </div>
    <div class="content">
      <p>Your inbox is getting full, would you like us to enable automatic archiving of old messages?</p>
    </div>
    <div class="actions">
      <div class="ui red basic cancel inverted button" (click)="noModal()">
        <i class="remove icon"></i>
        No
      </div>
      <div class="ui green ok inverted button" (click)="yesModal()">
        <i class="checkmark icon"></i>
        Yes
      </div>
    </div>
  </div>
</div>

 

  5-3 컴포넌트 클래스에서 template에서 사용하는 메소드를 정의한다.

    5-3-1 yesModal, noModal 메소드를 지정하였고 모두 modal 을 숨기기 위해 closeModal을 호출한다.

    5-3-2 closeModal을 부모클래스에게 close 이벤트를 발송하여 modal의 상태를 변경한다.

 

import { Component, OnInit, ElementRef, Output, EventEmitter } from '@angular/core'

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

  @Output() close = new EventEmitter()

  constructor(private element: ElementRef) { }

  ngOnInit(): void {
    document.body.appendChild(this.element.nativeElement)
  }

  ngOnDestroy() {
    this.element.nativeElement.remove();
  }

  noModal() {
    console.log('no modal');
    this.closeModal()
  }

  yesModal() {
    console.log('yes modal');
    this.closeModal()
  }

  closeModal() {
    this.close.emit()
  }
}

 

6. 추가로 만약 modal의 영역이 중요하고 내용이 표출되는 곳은 클릭해도 화면이 닫히지 않게 하려면

  6-1 아래와 같이 modal 영역을 클릭시에 클릭이벤트가 전파되지 않도록 

    6-1-1 (click)=$event.stopProgation() 를 붙여 준다. 이렇게 하면 실제 modal 영역 클릭 시 화면이 hidden되지 않는다.

 

<div class="ui dimmer visible active" (click)="closeModal()">
  <div class="ui modal visible active" (click)="$event.stopPropagation()">
    <i class="close icon" (click)="closeModal()"></i>
    <div class="header">
      <ng-content select="[modalTitle]"></ng-content>
    </div>
    <div class="content">
      <ng-content></ng-content>
    </div>
    <div class="actions">
      <ng-content select="[modalFooter]"></ng-content>
    </div>
    <div class="actions actions-default">
      <div class="ui button" (click)="closeModal()">OK</div>
    </div>
  </div>
</div>
728x90
댓글