12/08/2018, 18:03

Sử dụng dynamic component loader trong Angular

Dynamic component loader là gì. Dynamic component loader là một phương pháp giúp ứng dụng có thể khởi tạo một component ngay tại runtime. Áp dụng thực tế Load Bootstrap modal bằng Dynamic component loader Mình sẽ lấy một ví dụ về việc load Bootstrap modal trong Angular. Việc sử dụng modal ...

Dynamic component loader là gì.

Dynamic component loader là một phương pháp giúp ứng dụng có thể khởi tạo một component ngay tại runtime.

Áp dụng thực tế

Load Bootstrap modal bằng Dynamic component loader

Mình sẽ lấy một ví dụ về việc load Bootstrap modal trong Angular. Việc sử dụng modal trong Angular có một vài cách sau:

Chỉ ẩn modal trên UI: Ưu điểm: Bảo toàn được hiệu ứng hiện - ẩn của modal Nhược điểm: Phải rất chú ý tới việc unsubscribe các event handler. Việc ẩn modal trên UI, modal component vẫn đang tồn tại và tất cả những subscribers của một đối tượng Observable sẽ vẫn tiếp tục subscribe. Nếu bạn có một thao tác subscribe (tương tự binding event handler) nào đấy dựa vào event đóng mở modal, bạn sẽ cần cẩn trọng unsubscribe (tương tự unbinding event handler) trước khi ẩn popup, tránh việc 1 event handler bị subscriber nhiều lần sau mỗi lần mở modal.

Ẩn hiện modal trên DOM dựa vào directive ngIf: Ưu điểm: OnDestroy hook của component sẽ được gọi, tất cả các subscribers sẽ được unsubscribe tự động, bạn sẽ ko cần chủ động unsubscribe các subscribers mỗi lần đóng modal. Nhược điểm: Hiệu ứng xuất hiện của modal không hoạt động, bạn sẽ phải tự implement hiệu ứng bằng Angular animation.

Với việc sử dụng dynamic component, bạn có được ưu điểm của cả 2 cách trên.

Cách thực hiện:

Giả sử chúng ta có một module với cấu trúc như sau:

Giao diện của module này sẽ như sau:

message-list component sẽ hiển thị danh sách các tin nhắn, khi click nút 新規メッセージ, chúng ta sẽ load create-message-modal component.

Trước tiên, để load được một component, chúng ta cần có một chỗ chứa nó. Trong file message-list.component.html, chúng ta tạo một thẻ ng-container với directive appMessageModalContainer

 

<ng-container appMessageModalContainer></ng-container>

Tiếp theo chúng ta sẽ implement appMessageModalContainer dirrective:

import { Directive, ViewContainerRef } from '@angular/core';

@Directive({
  selector: '[appMessageModalContainer]'
})
export class MessageModalContainerDirective {
  constructor(public viewContainerRef: ViewContainerRef) {
  }
}

Chúng ta sẽ cần viện đến 2 method của ViewContainerRef giúp tạo và xoá component bên trong element.

Tiếp theo, trong message-list.component.ts:

import { Component, ComponentFactoryResolver, ViewChild } from '@angular/core';
import { MessageModalContainerDirective } from '../message-modal-container.directive';
import { CreateMessageModalComponent } from '../create-message-modal/create-message-modal.component';

@Component({
  selector: 'app-messages-list',
  templateUrl: './messages-list.component.html',
  styleUrls: ['./messages-list.component.scss'],
  entryComponents: [
    CreateMessageModalComponent
  ]
})
export class MessagesListComponent {
  @ViewChild(MessageModalContainerDirective) messageModalContainer: MessageModalContainerDirective;

  constructor(private componentFactoryResolver: ComponentFactoryResolver) {
  }

  handleCreateMessageButtonClick() {
    const viewContainerRef = this.messageModalContainer.viewContainerRef;
    const componentFactory = this.componentFactoryResolver.resolveComponentFactory(CreateMessageModalComponent);
    viewContainerRef.clear();
    const componentRef = viewContainerRef.createComponent(componentFactory);
    const createMessageModalInstance = <CreateMessageModalComponent>componentRef.instance;
    createMessageModalInstance.onMessageCreated.subscribe((staffsMessage: StaffsMessage) => {
      // do something
    });
    createMessageModalInstance.onModalHidden.subscribe(() => {
      this.messageModalContainer.viewContainerRef.clear();
    });
  }
}

Các điểm cần chú ý:

  • Bạn sẽ cần phải định nghĩa entryComponents trong component decorator để message-list component có thể biết được create-message component.
  • Sử dụng ComponentFactoryResolver.resolveComponentFactory() để tạo một componentFactory, và sử dụng method createComponent(componentFactory) của ViewContainerRef để khởi tạo một component instance bên trong directive.
  • Sau khi khởi tạo component instance, bạn có thể thoải mái tương tác với component.
  • Sau khi modal đóng, sử dụng ViewContainerRef để xoá component instance khỏi directive.

Kết

Documentation chi tiết: https://angular.io/guide/dynamic-component-loader

0