From eb84e5f34801445fd0ff4b3764e9d3f7d6a6e251 Mon Sep 17 00:00:00 2001 From: Valentin Mihai Date: Wed, 25 Jan 2023 22:01:28 +0200 Subject: [PATCH] added dynamic input component --- src/assets/styles/common-inputs.scss | 6 +- src/lib/dialog/base-dialog.component.ts | 8 ++- .../dynamic-input.component.html | 39 +++++++++++ .../dynamic-input.component.scss | 5 ++ .../dynamic-input/dynamic-input.component.ts | 65 +++++++++++++++++++ src/lib/inputs/index.ts | 1 + src/lib/inputs/inputs.module.ts | 11 ++-- 7 files changed, 129 insertions(+), 6 deletions(-) create mode 100644 src/lib/inputs/dynamic-input/dynamic-input.component.html create mode 100644 src/lib/inputs/dynamic-input/dynamic-input.component.scss create mode 100644 src/lib/inputs/dynamic-input/dynamic-input.component.ts diff --git a/src/assets/styles/common-inputs.scss b/src/assets/styles/common-inputs.scss index 5a02c00..239e98a 100644 --- a/src/assets/styles/common-inputs.scss +++ b/src/assets/styles/common-inputs.scss @@ -1,9 +1,13 @@ @use 'common-mixins' as mixins; -form .iqser-input-group:not(first-of-type) { +form .iqser-input-group:not(first-of-type), iqser-dynamic-input:not(first-of-type) { margin-top: 14px; } +iqser-dynamic-input { + display: flex; +} + .iqser-input-group { display: flex; flex-direction: column; diff --git a/src/lib/dialog/base-dialog.component.ts b/src/lib/dialog/base-dialog.component.ts index 13a500e..b3a867d 100644 --- a/src/lib/dialog/base-dialog.component.ts +++ b/src/lib/dialog/base-dialog.component.ts @@ -26,6 +26,7 @@ export abstract class BaseDialogComponent implements OnDestroy { protected readonly _toaster = inject(Toaster); readonly #confirmationDialogService = inject(ConfirmationDialogService); readonly #dialog = inject(MatDialog); + #hasErrors = false; #backdropClickSubscription = this._dialogRef.backdropClick().subscribe(() => { this.close(); }); @@ -41,7 +42,7 @@ export abstract class BaseDialogComponent implements OnDestroy { } get disabled(): boolean { - return !this.valid || !this.changed; + return !this.valid || !this.changed || this.#hasErrors; } abstract save(options?: SaveOptions): void; @@ -82,6 +83,11 @@ export abstract class BaseDialogComponent implements OnDestroy { } } + @HostListener('window:keyup', ['$event']) + onKeyUp(): void { + this.#hasErrors = !!document.getElementsByClassName('ng-invalid')[0]; + } + protected _openConfirmDialog() { const dialogRef = this.#confirmationDialogService.openDialog({ disableConfirm: !this.valid }); return firstValueFrom(dialogRef.afterClosed()); diff --git a/src/lib/inputs/dynamic-input/dynamic-input.component.html b/src/lib/inputs/dynamic-input/dynamic-input.component.html new file mode 100644 index 0000000..8b710c8 --- /dev/null +++ b/src/lib/inputs/dynamic-input/dynamic-input.component.html @@ -0,0 +1,39 @@ + +
+ + + + + + + + + + + + + + +
diff --git a/src/lib/inputs/dynamic-input/dynamic-input.component.scss b/src/lib/inputs/dynamic-input/dynamic-input.component.scss new file mode 100644 index 0000000..1c032f3 --- /dev/null +++ b/src/lib/inputs/dynamic-input/dynamic-input.component.scss @@ -0,0 +1,5 @@ +.datepicker-wrapper { + .mat-datepicker-input { + width: 100%; + } +} diff --git a/src/lib/inputs/dynamic-input/dynamic-input.component.ts b/src/lib/inputs/dynamic-input/dynamic-input.component.ts new file mode 100644 index 0000000..3ed50a7 --- /dev/null +++ b/src/lib/inputs/dynamic-input/dynamic-input.component.ts @@ -0,0 +1,65 @@ +import { ChangeDetectionStrategy, Component, forwardRef, Input, OnInit, Optional, Self } from '@angular/core'; +import { ControlValueAccessor, FormControl, NG_VALIDATORS, NG_VALUE_ACCESSOR, NgControl, ValidationErrors } from '@angular/forms'; +import { FormFieldComponent } from '../form-field/form-field-component.directive'; + +const InputTypes = { + DATE: 'DATE', + NUMBER: 'NUMBER', + TEXT: 'TEXT', + IMAGE: 'IMAGE', +} as const; + +export type InputType = keyof typeof InputTypes; + +type DynamicInput = number | string | Date; + +@Component({ + selector: 'iqser-dynamic-input [label] [type]', + templateUrl: './dynamic-input.component.html', + styleUrls: ['./dynamic-input.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, + providers: [ + { + provide: NG_VALUE_ACCESSOR, + multi: true, + useExisting: DynamicInputComponent, + }, + { + provide: NG_VALIDATORS, + multi: true, + useExisting: DynamicInputComponent, + }, + ] +}) +export class DynamicInputComponent extends FormFieldComponent { + + @Input() label!: string; + + @Input() type!: InputType; + + @Input() placeholder?: string; + + @Input() id?: string; + + @Input() name?: string; + + @Input() classList?: string = ''; + + @Input() input!: DynamicInput; + + get isDate() { + return this.type === InputTypes.DATE; + } + + get isNumber() { + return this.type === InputTypes.NUMBER; + } + + get isText() { + return this.type === InputTypes.TEXT; + } + + writeValue(input: DynamicInput): void { + this.input = input; + } +} diff --git a/src/lib/inputs/index.ts b/src/lib/inputs/index.ts index a7f132c..cd561f1 100644 --- a/src/lib/inputs/index.ts +++ b/src/lib/inputs/index.ts @@ -5,3 +5,4 @@ export * from './input-with-action/input-with-action.component'; export * from './details-radio/details-radio.component'; export * from './details-radio/details-radio-option'; export * from './form-field/form-field-component.directive'; +export * from './dynamic-input/dynamic-input.component'; diff --git a/src/lib/inputs/inputs.module.ts b/src/lib/inputs/inputs.module.ts index 9cd024d..866e87f 100644 --- a/src/lib/inputs/inputs.module.ts +++ b/src/lib/inputs/inputs.module.ts @@ -1,6 +1,6 @@ import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; -import { FormsModule } from '@angular/forms'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { IqserButtonsModule } from '../buttons'; import { RoundCheckboxComponent } from './round-checkbox/round-checkbox.component'; import { EditableInputComponent } from './editable-input/editable-input.component'; @@ -8,13 +8,16 @@ import { InputWithActionComponent } from './input-with-action/input-with-action. import { IqserIconsModule } from '../icons'; import { DetailsRadioComponent } from './details-radio/details-radio.component'; import { TranslateModule } from '@ngx-translate/core'; +import { DynamicInputComponent } from './dynamic-input/dynamic-input.component'; +import { MatDatepickerModule } from '@angular/material/datepicker'; +import { MatInputModule } from '@angular/material/input'; -const modules = [IqserButtonsModule, FormsModule]; -const components = [RoundCheckboxComponent, EditableInputComponent, InputWithActionComponent, DetailsRadioComponent]; +const modules = [IqserButtonsModule, FormsModule, ReactiveFormsModule, MatDatepickerModule]; +const components = [RoundCheckboxComponent, EditableInputComponent, InputWithActionComponent, DetailsRadioComponent, DynamicInputComponent]; @NgModule({ declarations: [...components], exports: [...components], - imports: [CommonModule, IqserIconsModule, TranslateModule, ...modules], + imports: [CommonModule, IqserIconsModule, TranslateModule, ...modules, MatInputModule], }) export class IqserInputsModule {}