From afed414030f936da36aa993a1945591b5c451861 Mon Sep 17 00:00:00 2001 From: Valentin Date: Wed, 12 Jan 2022 13:11:54 +0200 Subject: [PATCH] moved 'base-dialog component' and 'confirmation-dialog service' in common --- src/lib/dialog/base-dialog.component.ts | 96 +++++++++++++++++-- src/lib/dialog/confirmation-dialog.service.ts | 39 ++++++++ 2 files changed, 129 insertions(+), 6 deletions(-) create mode 100644 src/lib/dialog/confirmation-dialog.service.ts diff --git a/src/lib/dialog/base-dialog.component.ts b/src/lib/dialog/base-dialog.component.ts index 13d1e7b..33f5289 100644 --- a/src/lib/dialog/base-dialog.component.ts +++ b/src/lib/dialog/base-dialog.component.ts @@ -1,5 +1,10 @@ -import { Directive, HostListener } from '@angular/core'; -import { IqserEventTarget } from '../utils'; +import { Directive, HostListener, Injector, OnInit } from '@angular/core'; +import { MatDialogRef } from '@angular/material/dialog'; +import { FormGroup } from '@angular/forms'; +import * as moment from 'moment'; +import { AutoUnsubscribe, IqserEventTarget } from '../utils'; +import { ConfirmOptions } from '../misc'; +import { ConfirmationDialogService } from './confirmation-dialog.service'; @Directive() /** @@ -12,12 +17,84 @@ import { IqserEventTarget } from '../utils'; * Make sure to remove the (submit)="save()" property from the form and to set type="button" on the save button * (otherwise the save request will be triggered twice). * */ -export abstract class BaseDialogComponent { - abstract changed: boolean; - abstract valid: boolean; +export abstract class BaseDialogComponent extends AutoUnsubscribe implements OnInit { abstract disabled: boolean; - abstract save(): void; + protected readonly _dialogService: ConfirmationDialogService = this._injector.get(ConfirmationDialogService); + protected _waitingForConfirmation = false; + + form!: FormGroup; + initialFormValue; + + constructor(protected readonly _injector: Injector, protected readonly _dialogRef: MatDialogRef) { + super(); + } + + abstract save(closeAfterSave?: boolean): void; + + ngOnInit(): void { + this.addSubscription = this._dialogRef.backdropClick().subscribe(() => { + this.close(); + }); + } + + get valid(): boolean { + return this.form.valid; + } + + get changed(): boolean { + for (const key of Object.keys(this.form.getRawValue())) { + const initialValue = this.initialFormValue[key]; + const updatedValue = this.form.get(key).value; + + if (initialValue == null && updatedValue != null) { + const updatedValueType = typeof updatedValue; + if (updatedValueType !== 'string' && updatedValueType !== 'boolean') { + return true; + } else if (updatedValueType === 'string' && updatedValue.length > 0) { + return true; + } else if (updatedValueType === 'boolean' && updatedValue === true) { + return true; + } + } else if (initialValue !== updatedValue) { + if (Array.isArray(updatedValue)) { + if (JSON.stringify(initialValue) !== JSON.stringify(updatedValue)) { + return true; + } + } else if (updatedValue instanceof moment) { + if (!moment(updatedValue).isSame(moment(initialValue))) { + return true; + } + } else { + return true; + } + } + } + return false; + } + + close(): void { + if (this.changed) { + this._openConfirmDialog().then(result => { + if (result in ConfirmOptions) { + if (result === ConfirmOptions.CONFIRM) { + this.save(true); + } else { + this._dialogRef.close(); + } + } + this._waitingForConfirmation = false; + }); + } else { + this._dialogRef.close(); + } + } + + protected _openConfirmDialog() { + this._waitingForConfirmation = true; + const dialogRef = this._dialogService.openDialog({ disableConfirm: !this.valid }); + return dialogRef.afterClosed().toPromise(); + } @HostListener('window:keydown.Enter', ['$event']) onEnter(event: KeyboardEvent): void { @@ -26,4 +103,11 @@ export abstract class BaseDialogComponent { this.save(); } } + + @HostListener('window:keydown.Escape', ['$event']) + onEscape(): void { + if (!this._waitingForConfirmation) { + this.close(); + } + } } diff --git a/src/lib/dialog/confirmation-dialog.service.ts b/src/lib/dialog/confirmation-dialog.service.ts new file mode 100644 index 0000000..16f8a1e --- /dev/null +++ b/src/lib/dialog/confirmation-dialog.service.ts @@ -0,0 +1,39 @@ +import { Injectable } from '@angular/core'; +import { MatDialog, MatDialogRef } from '@angular/material/dialog'; +import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; +import { ConfirmationDialogComponent, ConfirmationDialogInput, DialogConfig, TitleColors } from '@iqser/common-ui'; +import { DialogService } from '../services/dialog.service'; + +type DialogType = 'confirm'; + +@Injectable({ + providedIn: 'root', +}) +export class ConfirmationDialogService extends DialogService { + protected readonly _config: DialogConfig = { + confirm: { + component: ConfirmationDialogComponent, + dialogConfig: { disableClose: false }, + }, + }; + + constructor(protected readonly _dialog: MatDialog) { + super(_dialog); + } + + openDialog(data?): MatDialogRef { + return super.openDialog( + 'confirm', + null, + new ConfirmationDialogInput({ + title: _('confirmation-dialog.unsaved-changes.title'), + question: _('confirmation-dialog.unsaved-changes.question'), + details: _('confirmation-dialog.unsaved-changes.details'), + confirmationText: _('confirmation-dialog.unsaved-changes.confirmation-text'), + discardChangesText: _('confirmation-dialog.unsaved-changes.discard-changes-text'), + disableConfirm: data.disableConfirm, + titleColor: TitleColors.WARN, + }), + ); + } +}