Criando um modal com conteúdo dinâmico - Angular

18856 단어 angular
Olá eu sou o Goku, meu primeiro post aqui 🎉, talvez você já tenha passado por uma situação de criar um componente com conteúdo de outro, existem algumas maneiras de criar um componente de forma dinâmica, para exemplificar esse comportamento vou utilizar como exemplo a implementação de um modal que tem seu conteúdo (corpo) modificado através de outro componente, vamos para a prática:

Vamos começar implementando nosso componente de modal, onde teremos os botões de concluir, cancelar, título e corpo (dinâmico).

import {
  Component,
  ComponentFactoryResolver,
  EventEmitter,
  Input,
  OnDestroy,
  OnInit,
  Output,
  ViewChild,
  ViewContainerRef,
} from '@angular/core';
import { ComponentType } from '@angular/cdk/overlay';

@Component({
  selector: 'dynamic-modal',
  templateUrl: 'dynamic-modal.component.html',
  styleUrls: ['dynamic-modal.component.less'],
})
export class DynamicModalComponent implements OnInit, OnDestroy {
  constructor(private resolverFactory: ComponentFactoryResolver) {
  }

  @Input() title: string = '';
  @Input() body!: ComponentType<{}>;
  @Output() closeMeEvent = new EventEmitter();
  @Output() confirmEvent = new EventEmitter();

  @ViewChild('viewContainer', {read: ViewContainerRef, static: false}) viewContainer!: ViewContainerRef;

  ngOnInit(): void {
    console.log('Modal init');
  }

  closeMe() {
    this.closeMeEvent.emit();
  }
  confirm() {
    this.confirmEvent.emit();
  }

  ngOnDestroy(): void {
    console.log('Modal destroyed');
  }

  ngAfterViewInit() {
    const factory = this.resolverFactory.resolveComponentFactory(this.body as any);
    this.viewContainer.createComponent(factory);
  }
}


Nosso body será or componente informado via service que será renderizado por nossa factory como está implementado no ngAfterViewInit.

HTML은 모달 구성 요소에 대한 추가 정보를 제공합니다. Você sabia que os componentes do angular são desse tipo? ComponentType.

<div
  style="
    width: 500px;
    height: auto;
    border: 1px solid black;
    background-color: white;
    border-radius: 15px;
    display: flex;
    justify-content: center;
    align-items: center;
    flex-direction: column;
  "
>
  <h1 class="title">{{ title }}</h1>
  <div #viewContainer></div>
  <div>
    <button (click)="closeMe()">Fechar</button>
    <button (click)="confirm()">Salvar</button>
  </div>
</div>


div que contém #viewContainer será responsável por renderizar nosso conteúdo dinâmico. Para chamar o modal que acabamos de criar vamos precisar adicionar um serviço que será responsável por receber os parametros necessários para a construção do modal como título e conteúdo(body dinâmico). Segue abaixo a implementação do service.

import {
  ComponentFactoryResolver,
  ComponentRef,
  Injectable,
  ViewContainerRef,
} from '@angular/core';
import { Subject } from 'rxjs';
import { DynamicModalComponent } from './dynamic-modal.component';
import { ComponentType } from '@angular/cdk/overlay'; 

@Injectable({ providedIn: 'root' })
export class ModalService {
  private componentRef!: ComponentRef<DynamicModalComponent>;
  private componentSubscriber!: Subject<string>;
  constructor(private resolver: ComponentFactoryResolver) {}

  openModal(entry: ViewContainerRef, modalTitle: string, modalBody: ComponentType<{}>) {
    let factory = this.resolver.resolveComponentFactory(DynamicModalComponent);
    this.componentRef = entry.createComponent(factory);
    this.componentRef.instance.title = modalTitle;
    this.componentRef.instance.body = modalBody;
    this.componentRef.instance.closeMeEvent.subscribe(() => this.closeModal());
    this.componentRef.instance.confirmEvent.subscribe(() => this.confirm());
    this.componentSubscriber = new Subject<string>();
    return this.componentSubscriber.asObservable();
  }

  closeModal() {
    this.componentSubscriber.complete();
    this.componentRef.destroy();
  }

  confirm() {
    this.componentSubscriber.next('confirm');
    this.closeModal();
  }
}



esse serviço é responsável por informar os @Inputs do nosso DynamicModalComponent, note que informamos o conteúdo do modal na seguinte linha this.componentRef.instance.body = modalBody; , agora nós temos um serviço que cria nosso modal (DynamicModalComponent) com título e conteúdo dinâmicos, com isso só precisamos agora chamar nosso serviço e informar os conteúdos para ele, essa é a parte que nós vamos chamar no dia a dia para criar um modal . Na tela que você precisa chamar o modal adicione os seguintes códigos:

constructor(private modalService: ModalService) {}

@ViewChild('modal', { read: ViewContainerRef, static: true })
  entry!: ViewContainerRef;
  sub!: Subscription;

openModal() {
// MyComponent é o componente que será renderizado dentro do seu body
    this.sub = this.modalService
      .openModal(this.entry, 'Título do modal', MyComponent)
      .subscribe((v) => {
        // dispara quando é aberto o modal
      });
  }


추가 HTML 정확도가 없으며 OpenModal의 기능과 ViewChild 로컬리자에 대한 태그가 표시되지 않습니다.

<button
  (click)="openModal()"
  data-testid="button-login"
>
 Abrir Modal
</button>

<div #modal></div>


e 프론티노! Aconselho fortemente criar um module separado para adicionar seus modais contents e esse componente de modal com o serviço dentro do mesmo modulo. Crie também um modelo bacana de modal não use esse layout maravilhoso do post para o projeto kkk e defina como padrão para todo o seu sistema, caso um dia o modal venha a ser alterado você precisará alterar somente em um local (modal.component.html ).

É isso pessoal, espero que eu tenha conseguido contribuir com o desenvolvimento de vocês, também tenho que aprender e me empenhar para escrever mais por aqui então qualquer 피드백
vai ser muito construtivo, obrigado! 🍻

좋은 웹페이지 즐겨찾기