typescript - Vytvorte znovu použiteľnú modálnu komponentu v Angular


Podľa tohto tutoriálu som vytvoril opakovane použiteľnú a prispôsobiteľnú modálnu komponentu. Avšak mám jeden problém. Predstavte si, že sú dve komponenty, A a B, a v oboch otvorím modál pomocou modálnej komponenty. Pre komponentu A, keď používateľ klikne na tlačidlo odoslať, musí sa vykonať functionA() komponentu A, a pre B functionB() komponentu B. Ako môžem umožniť súboru modal.ts prístup k obom funkciám a ich vykonanie?

Ak je to možné, nechcem mať globálny súbor služieb, kde sú všetky funkcie, ani presúvať všetky súvisiace funkcie do súboru modal.ts, radšej si chcem udržať každý jednotlivý komponent čistý a oddelený, ale optimalizovať interakciu medzi nimi tak, aby som len odovzdával názov funkcie a požadované vstupné argumenty. Vie niekto, aká je najlepšia prax na dosiahnutie tohto? Vopred ďakujem.

.ts modálu:

  open(): Promise<boolean> {
     ...
  }

  async close(): Promise<void> {
      const result = await this.modalConfig.onClose();
      this.modalRef.close(result);  
  }

  async dismiss(): Promise<void> {
    ...
  }
}

config.ts modalu:

export class ModalConfig {
  modalTitle: string;
  data: string = '';
  onClose?(): Promise<boolean> | boolean;
}

.html modálneho okna:

<ng-template #modal>
  <div class="modal-header">
    <button type="button" (click)="dismiss()">cancel</button>
    <button type="button" (click)="close()">Ok</button>
  </div>
</ng-template>

Odpoveď č. 1

Vytvoril som túto jednoduchú fungujúcu verziu, aby ste pochopili modulárnu komponentu modálneho okna, prosím, prejdite si kód a dajte mi vedieť, ak by boli nejaké problémy, môžeme modálne okno napísať raz a ľahko ho používať v celom aplikácii!

modálna komponenta

html

<div
  class="modal"
  tabindex="-1"
  role="dialog"
  *ngIf="open"
  style="display:block;"
>
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title">{{ config.title }}</h5>
        <button
          type="button"
          class="close"
          data-dismiss="modal"
          aria-label="Close"
          (click)="discardWrapper($event)"
        >
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body">
        <p>{{ config.description }}</p>
      </div>
      <div class="modal-footer">
        <button
          type="button"
          class="btn btn-primary"
          (click)="saveWrapper($event)"
        >
          Save changes
        </button>
        <button
          type="button"
          class="btn btn-secondary"
          data-dismiss="modal"
          (click)="discardWrapper($event)"
        >
          Close
        </button>
      </div>
    </div>
  </div>
</div>

ts

import { CommonModule } from '@angular/common';
import { Component, OnInit } from '@angular/core';
import { ModalService } from './modal.service';

export class ModalConfig {
  title?: string = '';
  description?: string = '';
  save?: Function = () => {};
  discard?: Function = () => {};

  constructor(
    title: string = '',
    description: string = '',
    save = null,
    discard = null
  ) {
    if (title) this.title = title;
    if (description) this.description = description;
    if (save) this.save = save;
    if (discard) this.discard = discard;
  }
}

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

  get open() {
    return this.modalService.isOpen;
  }

  get config() {
    return this.modalService.config;
  }

  discardWrapper(event: Event) {
    this.modalService.isOpen = false;
    if (this.config.discard) {
      this.config.discard(event);
    }
  }

  saveWrapper(event: Event) {
    this.modalService.isOpen = false;
    if (this.config.save) {
      this.config.save(event);
    }
  }

  ngOnInit() {}
}

služba

import { Injectable } from '@angular/core';
import { ModalConfig } from './modal.component';

@Injectable({
  providedIn: 'root',
})
export class ModalService {
  isOpen = false;
  config = new ModalConfig();

  constructor() {}

  open(config: ModalConfig) {
    this.config = { ...this.config, ...config };
    this.isOpen = true;
  }
}

Komponent používajúci túto logiku

ts

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

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

  ngOnInit() {}

  openModal() {
    this.modalService.open({
      title: 'test',
      description: 'test description',
    });
  }
}

html

<p>a works!</p>

<button (click)="openModal()" class="btn btn-primary">open modal</button>

stackblitz

Odpoveď č. 2

Presuňte metódy dismiss() a close() do služby a volajte ich odtiaľ. Toto by malo vyriešiť váš problém.

Súvisiace články