© 2020, Developed by Hieu Dev

Hướng dẫn tạo Modal mà không sử dụng Bootstrap trong Angular

Hôm nay, mình sẽ hướng dẫn các bạn cách tạo popup modal mà không sử dụng Bootstrap hay bất kỳ npm dependency nào. Các bước thực hiện rất đơn giản, các bạn có thể dễ dàng kế thừa và túy biến theo ý của bạn.

Hướng dẫn tạo Modal mà không sử dụng Bootstrap trong Angular

Khi triển khai web app, các bạn chắc hẳn sẽ cần dùng đến Modal trong Bootstrap, nó được sử dụng để hiển thị một dialog (hộp thoại) hay popup (cửa sổ hiện lên) trên website. Nhưng trong vài trường hợp, bạn không muốn phụ thuộc vào Bootstrap mà muốn tự chủ toàn bộ, và đây là giải pháp chắc hẳn sẽ có ích với bạn.

Hướng dẫn tạo Modal trong Angular 

Đầu tiên, ta sẽ triển khai modal component:
src/app/_component/modal.component.html:

<div class="modal-popup">
    <div class="modal-popup-body">
        <ng-content></ng-content>
    </div>
</div>
<div class="modal-popup-background"></div>


src/app/_component/modal.component.ts:

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

import { ModalService } from '../_services/modal.service';

@Component({
    selector: 'modal-popup',
    templateUrl: './modal.component.html'
})
export class ModalComponent implements OnInit, OnDestroy {
    @Input() id: string;
    private element: any;

    constructor(private modalService: ModalService, private el: ElementRef) {
        this.element = el.nativeElement;
    }

    ngOnInit(): void {
        let modal = this;

        // ensure id attribute exists
        if (!this.id) {
            console.error('modal must have an id');
            return;
        }

        // move element to bottom of page (just before </body>) so it can be displayed above everything else
        document.body.appendChild(this.element);

        // close modal on background click
        this.element.addEventListener('click', function (e: any) {
            if (e.target.className === 'modal-popup') {
                modal.close();
            }
        });

        // add self (this modal instance) to the modal service so it's accessible from controllers
        this.modalService.add(this);
    }

    // remove self from modal service when directive is destroyed
    ngOnDestroy(): void {
        this.modalService.remove(this.id);
        this.element.remove();
    }

    // open modal
    open(): void {
        this.element.style.display = 'block';
        document.body.classList.add('modal-popup-open');
        console.log('modal open called');
    }

    // close modal
    close(): void {
        this.element.style.display = 'none';
        document.body.classList.remove('modal-popup-open');
        console.log('modal close called');
    }
}    


Và tiếp theo, ta cần triển khai modal service, ta tạo file service với code sau:
src/app/_services/modal.service.ts:

import { Injectable } from '@angular/core';

@Injectable({ providedIn: 'root' })
export class ModalService {
    private modals: any[] = [];

    add(modal: any) {
        // add modal to array of active modals
        this.modals.push(modal);
    }

    remove(id: string) {
        // remove modal from array of active modals
        this.modals = this.modals.filter(x => x.id !== id);
    }

    open(id: string) {
        // open modal specified by id
        let modal: any = this.modals.filter(x => x.id === id)[0];
        modal.open();
    }

    close(id: string) {
        // close modal specified by id
        let modal: any = this.modals.filter(x => x.id === id)[0];
        modal.close();
    }
}


Lưu ý: Như các bạn thấy, mình đã sử dụng thư mục _component cho component, thư mục _services để chứa các file service, bạn có thể chọn theo lựa chọn của bạn cho đường dẫn hoặc tên thư mục nhưng hãy đảm bảo đúng các đường dẫn import trong các file code.

Khi có đã có component và service, ta cần tiến hành thêm style cho nó, như bạn được biết, khi một modal được mở lên, các thành phần khác hoàn toàn nằm bên dưới và được bao trùm lên một background tối màu. Cụ thể ta có code sau bên trong file style.scss:


modal-popup {
    display: none;

    .modal-popup {
        /* modal container fixed across whole screen */
        position: fixed;
        top: 0;
        right: 0;
        bottom: 0;
        left: 0;
        max-width:400px;
        min-width:300px;
        width:50%;
        margin:auto;
        min-height:300px;

        /* z-index must be higher than .modal-popup-background */
        z-index: 1000;
        
        /* enables scrolling for tall modals */
        overflow: auto;

        .modal-popup-body {
            padding: 20px;
            background: #fff;

            /* margin exposes part of the modal background */
            margin: 40px;
        }
    }

    .modal-popup-background {
        /* modal background fixed across whole screen */
        position: fixed;
        top: 0;
        right: 0;
        bottom: 0;
        left: 0;

        /* semi-transparent black  */
        background-color: #000;
        opacity: 0.75;
        z-index: 900;
    }
}

body.modal-popup-open {
    /* body overflow is hidden to hide main scrollbar when modal window is open */
    overflow: hidden;
}


Bây giờ, ta sẽ sử dụng thành quả modal vừa tạo, cụ thể ta tạo một about page với button dùng để mở modal, cụ thể với code sau đây:

src/app/about/about.component.html:

<p>about works!</p>
<div>
    <button (click)="openModal('modal1')">Open Modal 1</button>
</div>

<modal-popup id="modal1">
    <h1>A Custom Modal!</h1>
    <p>This is dummy text</p>
    <button (click)="closeModal('modal1');">Close</button>
</modal-popup>


Bây giờ, ta cần tạo các phương thức và các nút để mở nó. Bạn cần đảm bảo rằng hàm có tham số này sẽ được ánh xạ để modal nào bật lên sẽ được mở. Tại đây, bạn có thể thấy nút modal1 sẽ được nhấp với phương thức modal1. Tương tự như vậy, bạn có thể tạo nhiều nút và nhiều chế độ hơn theo bất kỳ tên nào hoặc như modal2, modal3.

src/app/about/about.component.ts:

import { Component, OnInit } from '@angular/core';
import { ModalService } from '../_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() {
      
  }

  openModal(id: string) {
      this.modalService.open(id);
  }

  closeModal(id: string) {
      this.modalService.close(id);
  }

}


Cuối cùng, ta cần config bên trong file app.module.ts như sau:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { AboutComponent } from './about/about.component';

import { ModalComponent } from './_components/modal.component';

@NgModule({
  declarations: [
    AppComponent,
    AboutComponent,
    ModalComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    FormsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }


Và đó cũng là bước cuối cùng trong bài hướng dẫn của chúng ta.

Lời kết

Như mục tiêu đề ra, ta hoàn toàn không sử dụng Bootstrap, và như thế bạn có thể dễ dàng customize theo ý bạn, với các bước thực hiện rất đơn giản và nhanh chóng.

Mong bài viết hữu ích đến các bạn.

Hieu Ho.

2 Nhận xét

Mới hơn Cũ hơn