graycoreio/daffodil

View on GitHub
libs/design/modal/src/service/modal.service.ts

Summary

Maintainability
A
0 mins
Test Coverage
import { AnimationEvent } from '@angular/animations';
import {
  OverlayRef,
  Overlay,
  GlobalPositionStrategy,
} from '@angular/cdk/overlay';
import { ComponentPortal } from '@angular/cdk/portal';
import {
  Injectable,
  Type,
  ComponentRef,
  Injector,
} from '@angular/core';

import { DaffModal } from '../modal/modal';
import { DaffModalConfiguration } from '../modal/modal-config';
import { DaffModalComponent } from '../modal/modal.component';

@Injectable()
export class DaffModalService {
  private _modals: Map<DaffModalComponent, DaffModal> = new Map();

  constructor(private overlay: Overlay) { }

  private defaultConfiguration: DaffModalConfiguration = {};

  private _attachModal(
    overlayRef: OverlayRef,
  ): ComponentRef<DaffModalComponent> {
    const modal = overlayRef.attach(
      new ComponentPortal(
        DaffModalComponent,
        undefined,
        Injector.create({
          providers: [{
            provide: DaffModalService,
            useValue: this,
          }],
        }),
      ),
    );
    modal.instance.reveal();
    return modal;
  }

  private _attachModalContent(
    component: Type<any>,
    modal: ComponentRef<DaffModalComponent>,
  ): void {
    modal.instance.attachContent(new ComponentPortal(component));
  }

  private _createOverlayRef(): OverlayRef {
    return this.overlay.create({
      hasBackdrop: true,
      positionStrategy: new GlobalPositionStrategy()
        .centerHorizontally()
        .centerVertically(),
      scrollStrategy: this.overlay.scrollStrategies.block(),
    });
  }

  private _removeModal(modal: DaffModal) {
    if (!this._modals.has(modal.modal.instance)) {
      throw new Error(
        'The Modal that you are trying to remove does not exist.',
      );
    }

    this._modals.delete(modal.modal.instance);

    modal.overlay.dispose();
  }

  open(
    component: Type<any>,
    configuration?: Partial<DaffModalConfiguration>,
  ): DaffModalComponent {
    const config = { ...this.defaultConfiguration, ...configuration };
    const _ref = this._createOverlayRef();
    const _modal = this._attachModal(_ref);
    const _attachedModal = this._attachModalContent(component, _modal);

    if (configuration?.ariaLabelledBy) {
      _modal.instance.ariaLabelledBy = configuration.ariaLabelledBy;
    }

    const modal: DaffModal = {
      modal: _modal,
      overlay: _ref,
    };

    this._modals.set(modal.modal.instance, modal);

    _ref
      .backdropClick()
      .subscribe(() =>
        config.onBackdropClicked
          ? config.onBackdropClicked()
          : this.close(modal.modal.instance),
      );
    return modal.modal.instance;
  }

  close(component: DaffModalComponent): void {
    component.hide();
    const modal = this._modals.get(component);

    modal.overlay.detachBackdrop();
    component.closedAnimationCompleted.subscribe(
      (e: AnimationEvent) => this._removeModal(modal),
    );
  }
}