All files / src/app/shared/components/common/modal-dialog modal-dialog.component.ts

82.14% Statements 23/28
66.66% Branches 8/12
75% Functions 6/8
81.48% Lines 22/27

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 13228x 28x                         28x 28x 28x                                                                             28x     4x   4x   4x                 4x   4x   4x           2x   2x   2x     1x     2x             1x 1x             1x 1x                                         4x      
import { DOCUMENT } from '@angular/common';
import {
  ChangeDetectionStrategy,
  Component,
  DestroyRef,
  EventEmitter,
  Inject,
  Input,
  OnDestroy,
  Output,
  TemplateRef,
  ViewChild,
  inject,
} from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { NgbModal, NgbModalOptions, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
import { Subject, race, take } from 'rxjs';
 
export interface ModalOptions extends NgbModalOptions {
  /**
   * Modal title string.
   */
  titleText?: string;
  /**
   * Optional modal confirm button text.
   */
  confirmText?: string;
  /**
   * Optional modal confirm button disabled.
   */
  confirmDisabled?: boolean;
  /**
   * Optional modal reject button text.
   */
  rejectText?: string;
}
 
/**
 * The Modal Dialog Component displays a generic (ng-bootstrap) modal, that shows a custom title and custom content.
 * It provides an optional footer that includes confirm and reject buttons.
 * It is possible to pass any data on show.
 * The also provided confirmed output emitter will return the previously passed data if the modal gets confirmed.
 *
 * @see https://ng-bootstrap.github.io/#/components/modal/api#NgbModal
 *
 * @example
 * <ish-modal-dialog [options]="options" (confirmed)="onConfirmed($event)">
 *   Dummy content
 * </ish-modal-dialog>
 */
@Component({
  selector: 'ish-modal-dialog',
  templateUrl: './modal-dialog.component.html',
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ModalDialogComponent<T> implements OnDestroy {
  @Input() options: ModalOptions;
 
  @Output() confirmed = new EventEmitter<T>();
 
  @Output() closed = new EventEmitter<T>();
 
  @Output() shown = new EventEmitter<T>();
 
  @ViewChild('template') modalDialogTemplate: TemplateRef<unknown>;
 
  // visible-for-testing
  ngbModalRef: NgbModalRef;
 
  data: T;
 
  private hide$ = new Subject<void>();
 
  private destroyRef = inject(DestroyRef);
 
  constructor(private ngbModal: NgbModal, @Inject(DOCUMENT) private document: Document) {}
 
  /**
   * Configure and show modal dialog.
   */
  show(data?: T) {
    this.data = data ? data : undefined;
 
    this.ngbModalRef = this.ngbModal.open(this.modalDialogTemplate, this.options);
 
    race(this.ngbModalRef.dismissed, this.hide$)
      .pipe(take(1), takeUntilDestroyed(this.destroyRef))
      .subscribe(() => {
        this.closed.emit(this.data);
      });
 
    this.shown.emit(this.data);
  }
 
  /**
   * Hides modal dialog.
   */
  hide() {
    this.ngbModalRef.close();
    this.hide$.next();
  }
 
  /**
   * Emits input data or undefined and hides modal.
   */
  confirm() {
    this.confirmed.emit(this.data);
    this.hide();
  }
 
  /**
   * Scrolls to an anchor element
   *
   * @param anchor The ID of the anchor element.
   */
  // not-dead-code
  scrollToAnchor(anchor: string) {
    Iif (this.options.scrollable) {
      const element = this.document.getElementById(anchor);
      Iif (element) {
        setTimeout(() => {
          element.scrollIntoView({ behavior: 'smooth', block: 'start', inline: 'nearest' });
        }, 200);
      }
    }
  }
 
  ngOnDestroy(): void {
    this.hide$.complete(); // complete open hide$ subscription
  }
}