diff --git a/lib/content-services/src/lib/dialogs/folder/folder.dialog.html b/lib/content-services/src/lib/dialogs/folder/folder.dialog.html index 14b8522ea3..744908e16b 100644 --- a/lib/content-services/src/lib/dialogs/folder/folder.dialog.html +++ b/lib/content-services/src/lib/dialogs/folder/folder.dialog.html @@ -15,15 +15,16 @@ adf-auto-focus /> - - + @if (form.controls['name'].errors?.required) { + {{ 'CORE.FOLDER_DIALOG.FOLDER_NAME.ERRORS.REQUIRED' | translate }} - - - + + } + @if (!form.controls['name'].errors?.required && form.controls['name'].errors?.message) { + {{ form.controls['name'].errors?.message | translate }} - - + + } diff --git a/lib/core/src/lib/form/components/form-renderer.component.scss b/lib/core/src/lib/form/components/form-renderer.component.scss index 1270c3c57c..ca94d41162 100644 --- a/lib/core/src/lib/form/components/form-renderer.component.scss +++ b/lib/core/src/lib/form/components/form-renderer.component.scss @@ -40,6 +40,7 @@ .adf-container-widget { .adf-grid-list { display: grid; + row-gap: 16px; &-column-view { display: flex; @@ -65,6 +66,7 @@ display: flex; flex-direction: column; flex: 1 1 auto; + gap: 16px; } &-item { diff --git a/lib/core/src/lib/form/components/widgets/amount/amount.widget.html b/lib/core/src/lib/form/components/widgets/amount/amount.widget.html index a94613e563..98de5bba26 100644 --- a/lib/core/src/lib/form/components/widgets/amount/amount.widget.html +++ b/lib/core/src/lib/form/components/widgets/amount/amount.widget.html @@ -10,7 +10,7 @@ >
- + @if ( (field.name || field?.required) && !field.leftLabels) { {{field.name | translate }} } @if(!enableDisplayBasedOnLocale) { {{ currency }}  diff --git a/lib/core/src/lib/form/components/widgets/date-time/date-time.widget.html b/lib/core/src/lib/form/components/widgets/date-time/date-time.widget.html index ec1c68d82b..26e1c3b8db 100644 --- a/lib/core/src/lib/form/components/widgets/date-time/date-time.widget.html +++ b/lib/core/src/lib/form/components/widgets/date-time/date-time.widget.html @@ -10,7 +10,8 @@
+ [floatLabel]="field.placeholder ? 'always' : null" + subscriptSizing="dynamic"> @if( (field.name || field?.required) && !field.leftLabels) { {{ field.name | translate }} ({{ field.dateDisplayFormat }}) @@ -36,9 +37,11 @@ [touchUi]="true" [timeInterval]="5" [disabled]="field.readOnly" /> + @if (datetimeInputControl.invalid && datetimeInputControl.touched && field.validationSummary?.message) { + + {{ field.validationSummary.message | translate:translateParameters }} + + } -
- -
diff --git a/lib/core/src/lib/form/components/widgets/date-time/date-time.widget.ts b/lib/core/src/lib/form/components/widgets/date-time/date-time.widget.ts index 67a6ff90ad..a01c2a9850 100644 --- a/lib/core/src/lib/form/components/widgets/date-time/date-time.widget.ts +++ b/lib/core/src/lib/form/components/widgets/date-time/date-time.widget.ts @@ -27,7 +27,6 @@ import { DatetimeAdapter, MAT_DATETIME_FORMATS, MatDatetimepickerModule } from ' import { TranslatePipe } from '@ngx-translate/core'; import { ADF_DATE_FORMATS, ADF_DATETIME_FORMATS, AdfDateFnsAdapter, AdfDateTimeFnsAdapter, DateFnsUtils } from '../../../../common'; import { FormService } from '../../../services/form.service'; -import { ErrorWidgetComponent } from '../error/error.component'; import { WidgetComponent } from '../widget.component'; import { ErrorMessageModel } from '../core/error-message.model'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @@ -46,13 +45,14 @@ import { ReactiveFormWidget } from '../reactive-widget.interface'; host: { '(click)': 'event($event)' }, - imports: [NgIf, TranslatePipe, MatFormFieldModule, MatInputModule, MatDatetimepickerModule, ReactiveFormsModule, ErrorWidgetComponent], + imports: [NgIf, TranslatePipe, MatFormFieldModule, MatInputModule, MatDatetimepickerModule, ReactiveFormsModule], encapsulation: ViewEncapsulation.None }) export class DateTimeWidgetComponent extends WidgetComponent implements OnInit, ReactiveFormWidget { minDate: Date; maxDate: Date; datetimeInputControl: FormControl = new FormControl(null); + translateParameters: Record = {}; public readonly formService = inject(FormService); private readonly destroyRef = inject(DestroyRef); @@ -116,6 +116,15 @@ export class DateTimeWidgetComponent extends WidgetComponent implements OnInit, this.resetErrors(); this.field.markAsValid(); } + this.updateTranslateParameters(); + } + + private updateTranslateParameters(): void { + if (this.field.validationSummary?.isActive()) { + this.translateParameters = this.field.validationSummary.getAttributesAsJsonObj(); + } else { + this.translateParameters = {}; + } } private handleErrors(errors: ValidationErrors): void { diff --git a/lib/core/src/lib/form/components/widgets/date/date.widget.html b/lib/core/src/lib/form/components/widgets/date/date.widget.html index 33f95f300b..419760512a 100644 --- a/lib/core/src/lib/form/components/widgets/date/date.widget.html +++ b/lib/core/src/lib/form/components/widgets/date/date.widget.html @@ -1,5 +1,5 @@
- + @@ -19,11 +19,10 @@ + @if (dateInputControl.invalid && dateInputControl.touched && field.validationSummary?.message) { + + {{ field.validationSummary.message | translate:translateParameters }} + + } -
- -
diff --git a/lib/core/src/lib/form/components/widgets/date/date.widget.ts b/lib/core/src/lib/form/components/widgets/date/date.widget.ts index f42b0ae940..ebdbc7956e 100644 --- a/lib/core/src/lib/form/components/widgets/date/date.widget.ts +++ b/lib/core/src/lib/form/components/widgets/date/date.widget.ts @@ -17,7 +17,6 @@ /* eslint-disable @angular-eslint/component-selector */ -import { NgIf } from '@angular/common'; import { Component, DestroyRef, inject, OnInit, ViewEncapsulation } from '@angular/core'; import { FormControl, ReactiveFormsModule, ValidationErrors, Validators } from '@angular/forms'; import { DateAdapter, MAT_DATE_FORMATS } from '@angular/material/core'; @@ -27,7 +26,6 @@ import { MatInputModule } from '@angular/material/input'; import { TranslatePipe } from '@ngx-translate/core'; import { ADF_DATE_FORMATS, AdfDateFnsAdapter, DateFnsUtils, DEFAULT_DATE_FORMAT } from '../../../../common'; import { FormService } from '../../../services/form.service'; -import { ErrorWidgetComponent } from '../error/error.component'; import { WidgetComponent } from '../widget.component'; import { ErrorMessageModel } from '../core/error-message.model'; import { parseISO } from 'date-fns'; @@ -53,13 +51,14 @@ import { ReactiveFormWidget } from '../reactive-widget.interface'; '(invalid)': 'event($event)', '(select)': 'event($event)' }, - imports: [MatFormFieldModule, TranslatePipe, MatInputModule, MatDatepickerModule, ReactiveFormsModule, ErrorWidgetComponent, NgIf], + imports: [MatFormFieldModule, TranslatePipe, MatInputModule, MatDatepickerModule, ReactiveFormsModule], encapsulation: ViewEncapsulation.None }) export class DateWidgetComponent extends WidgetComponent implements OnInit, ReactiveFormWidget { minDate: Date; maxDate: Date; startAt: Date; + translateParameters: Record = {}; dateInputControl: FormControl = new FormControl(null); @@ -126,6 +125,15 @@ export class DateWidgetComponent extends WidgetComponent implements OnInit, Reac this.resetErrors(); this.field.markAsValid(); } + this.updateTranslateParameters(); + } + + private updateTranslateParameters(): void { + if (this.field.validationSummary?.isActive()) { + this.translateParameters = this.field.validationSummary.getAttributesAsJsonObj(); + } else { + this.translateParameters = {}; + } } private handleErrors(errors: ValidationErrors): void { diff --git a/lib/core/src/lib/form/components/widgets/decimal/decimal.component.html b/lib/core/src/lib/form/components/widgets/decimal/decimal.component.html index f51f1e4c6d..191a6cf5e5 100644 --- a/lib/core/src/lib/form/components/widgets/decimal/decimal.component.html +++ b/lib/core/src/lib/form/components/widgets/decimal/decimal.component.html @@ -9,7 +9,7 @@
- + @if ( (field.name || field?.required) && !field.leftLabels) { {{ field.name | translate }} } + [errorStateMatcher]="errorStateMatcher" + (blur)="onBlur()" /> + @if (field.validationSummary?.message) { + + {{ field.validationSummary.message | translate:translateParameters }} + + } + @if (isInvalidFieldRequired() && isTouched()) { + + {{ 'FORM.FIELD.REQUIRED' | translate }} + + } - -
- - -
diff --git a/lib/core/src/lib/form/components/widgets/decimal/decimal.component.ts b/lib/core/src/lib/form/components/widgets/decimal/decimal.component.ts index 8a2c1cd51e..16fe6aff90 100644 --- a/lib/core/src/lib/form/components/widgets/decimal/decimal.component.ts +++ b/lib/core/src/lib/form/components/widgets/decimal/decimal.component.ts @@ -16,12 +16,12 @@ */ import { NgIf } from '@angular/common'; -import { Component, ViewEncapsulation } from '@angular/core'; -import { FormsModule } from '@angular/forms'; +import { Component, OnInit, ViewEncapsulation } from '@angular/core'; +import { FormsModule, FormGroupDirective, NgForm, UntypedFormControl } from '@angular/forms'; +import { ErrorStateMatcher } from '@angular/material/core'; import { MatFormFieldModule } from '@angular/material/form-field'; import { MatInputModule } from '@angular/material/input'; import { TranslatePipe } from '@ngx-translate/core'; -import { ErrorWidgetComponent } from '../error/error.component'; import { WidgetComponent } from '../widget.component'; @Component({ @@ -39,7 +39,34 @@ import { WidgetComponent } from '../widget.component'; '(invalid)': 'event($event)', '(select)': 'event($event)' }, - imports: [NgIf, TranslatePipe, MatFormFieldModule, MatInputModule, FormsModule, ErrorWidgetComponent], + imports: [NgIf, TranslatePipe, MatFormFieldModule, MatInputModule, FormsModule], encapsulation: ViewEncapsulation.None }) -export class DecimalWidgetComponent extends WidgetComponent {} +export class DecimalWidgetComponent extends WidgetComponent implements OnInit { + errorStateMatcher: ErrorStateMatcher; + translateParameters: Record = {}; + + ngOnInit(): void { + this.initErrorStateMatcher(); + } + + private initErrorStateMatcher(): void { + this.errorStateMatcher = { + isErrorState: (_control: UntypedFormControl | null, _form: FormGroupDirective | NgForm | null): boolean => + !this.field.isValid && this.isTouched() + }; + } + + private updateTranslateParameters(): void { + if (this.field.validationSummary?.isActive()) { + this.translateParameters = this.field.validationSummary.getAttributesAsJsonObj(); + } else { + this.translateParameters = {}; + } + } + + onBlur(): void { + this.markAsTouched(); + this.updateTranslateParameters(); + } +} diff --git a/lib/core/src/lib/form/components/widgets/multiline-text/multiline-text.widget.html b/lib/core/src/lib/form/components/widgets/multiline-text/multiline-text.widget.html index ef5b3d11cc..be530550d8 100644 --- a/lib/core/src/lib/form/components/widgets/multiline-text/multiline-text.widget.html +++ b/lib/core/src/lib/form/components/widgets/multiline-text/multiline-text.widget.html @@ -24,19 +24,26 @@ [disabled]="field.readOnly || readOnly" [placeholder]="field.placeholder" [title]="field.tooltip" - (blur)="markAsTouched()" + [errorStateMatcher]="errorStateMatcher" + (blur)="onBlur()" >
-
- {{ field?.value?.length || 0 }}/{{ field.maxLength }} -
-
- - + @if (field.maxLength > 0) { +
+ {{ field?.value?.length || 0 }}/{{ field.maxLength }} +
+ } +
+ @if (field.validationSummary?.message) { + + {{ field.validationSummary.message | translate:translateParameters }} + + } + @if (isInvalidFieldRequired() && isTouched()) { + + {{ 'FORM.FIELD.REQUIRED' | translate }} + + }
diff --git a/lib/core/src/lib/form/components/widgets/multiline-text/multiline-text.widget.scss b/lib/core/src/lib/form/components/widgets/multiline-text/multiline-text.widget.scss index 5c30d8f486..1d6a501fa4 100644 --- a/lib/core/src/lib/form/components/widgets/multiline-text/multiline-text.widget.scss +++ b/lib/core/src/lib/form/components/widgets/multiline-text/multiline-text.widget.scss @@ -26,6 +26,11 @@ padding-left: 0; } + &-multiline-error-container { + width: 100%; + font-size: var(--mat-sys-body-small-size); + } + &-multiline-required-message { display: flex; } diff --git a/lib/core/src/lib/form/components/widgets/multiline-text/multiline-text.widget.ts b/lib/core/src/lib/form/components/widgets/multiline-text/multiline-text.widget.ts index 541706b69a..42f1270e90 100644 --- a/lib/core/src/lib/form/components/widgets/multiline-text/multiline-text.widget.ts +++ b/lib/core/src/lib/form/components/widgets/multiline-text/multiline-text.widget.ts @@ -17,16 +17,15 @@ /* eslint-disable @angular-eslint/component-selector */ -import { NgIf } from '@angular/common'; import { Component, DestroyRef, inject, OnInit, ViewEncapsulation } from '@angular/core'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; -import { FormsModule } from '@angular/forms'; +import { FormsModule, FormGroupDirective, NgForm, UntypedFormControl } from '@angular/forms'; +import { ErrorStateMatcher } from '@angular/material/core'; import { MatFormFieldModule } from '@angular/material/form-field'; import { MatInputModule } from '@angular/material/input'; import { TranslatePipe } from '@ngx-translate/core'; import { isObservable } from 'rxjs'; import { ADF_CUSTOM_MESSAGE } from '../core/custom-validation-message.token'; -import { ErrorWidgetComponent } from '../error/error.component'; import { WidgetComponent } from '../widget.component'; @Component({ @@ -44,14 +43,18 @@ import { WidgetComponent } from '../widget.component'; '(invalid)': 'event($event)', '(select)': 'event($event)' }, - imports: [MatFormFieldModule, NgIf, TranslatePipe, MatInputModule, FormsModule, ErrorWidgetComponent], + imports: [MatFormFieldModule, TranslatePipe, MatInputModule, FormsModule], encapsulation: ViewEncapsulation.None }) export class MultilineTextWidgetComponentComponent extends WidgetComponent implements OnInit { private readonly destroyRef = inject(DestroyRef); private readonly enableCustomMessage = inject(ADF_CUSTOM_MESSAGE, { optional: true }); + errorStateMatcher: ErrorStateMatcher; + translateParameters: Record = {}; + ngOnInit(): void { + this.initErrorStateMatcher(); if (this.enableCustomMessage != null) { if (isObservable(this.enableCustomMessage)) { this.enableCustomMessage.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((enabled: boolean) => { @@ -66,4 +69,24 @@ export class MultilineTextWidgetComponentComponent extends WidgetComponent imple this.field.enableCustomValidationMessage = false; } } + + private initErrorStateMatcher(): void { + this.errorStateMatcher = { + isErrorState: (_control: UntypedFormControl | null, _form: FormGroupDirective | NgForm | null): boolean => + !this.field.isValid && this.isTouched() + }; + } + + private updateTranslateParameters(): void { + if (this.field.validationSummary?.isActive()) { + this.translateParameters = this.field.validationSummary.getAttributesAsJsonObj(); + } else { + this.translateParameters = {}; + } + } + + onBlur(): void { + this.markAsTouched(); + this.updateTranslateParameters(); + } } diff --git a/lib/core/src/lib/form/components/widgets/number/number.widget.html b/lib/core/src/lib/form/components/widgets/number/number.widget.html index 8f5749b960..26c164849c 100644 --- a/lib/core/src/lib/form/components/widgets/number/number.widget.html +++ b/lib/core/src/lib/form/components/widgets/number/number.widget.html @@ -9,7 +9,7 @@
- + @if( (field.name || this.field?.required) && !field.leftLabels) { {{ field.name | translate }} @@ -27,14 +27,18 @@ [disabled]="field.readOnly" [placeholder]="field.placeholder" [title]="field.tooltip" - (blur)="markAsTouched()"> + [errorStateMatcher]="errorStateMatcher" + (blur)="onBlur()"> + @if (field.validationSummary?.message) { + + {{ field.validationSummary.message | translate:translateParameters }} + + } + @if (isInvalidFieldRequired() && isTouched()) { + + {{ 'FORM.FIELD.REQUIRED' | translate }} + + } -
- - -
diff --git a/lib/core/src/lib/form/components/widgets/number/number.widget.ts b/lib/core/src/lib/form/components/widgets/number/number.widget.ts index 8cabe2a308..eff3e30c02 100644 --- a/lib/core/src/lib/form/components/widgets/number/number.widget.ts +++ b/lib/core/src/lib/form/components/widgets/number/number.widget.ts @@ -19,12 +19,12 @@ import { NgIf } from '@angular/common'; import { Component, inject, OnInit, ViewEncapsulation } from '@angular/core'; -import { FormsModule } from '@angular/forms'; +import { FormsModule, FormGroupDirective, NgForm, UntypedFormControl } from '@angular/forms'; +import { ErrorStateMatcher } from '@angular/material/core'; import { MatFormFieldModule } from '@angular/material/form-field'; import { MatInputModule } from '@angular/material/input'; import { TranslatePipe } from '@ngx-translate/core'; import { DecimalNumberPipe } from '../../../../pipes'; -import { ErrorWidgetComponent } from '../error/error.component'; import { WidgetComponent } from '../widget.component'; @Component({ @@ -42,12 +42,14 @@ import { WidgetComponent } from '../widget.component'; '(invalid)': 'event($event)', '(select)': 'event($event)' }, - imports: [NgIf, TranslatePipe, MatFormFieldModule, MatInputModule, FormsModule, ErrorWidgetComponent], + imports: [NgIf, TranslatePipe, MatFormFieldModule, MatInputModule, FormsModule], providers: [DecimalNumberPipe], encapsulation: ViewEncapsulation.None }) export class NumberWidgetComponent extends WidgetComponent implements OnInit { displayValue: number; + errorStateMatcher: ErrorStateMatcher; + translateParameters: Record = {}; private readonly decimalNumberPipe = inject(DecimalNumberPipe); @@ -57,6 +59,27 @@ export class NumberWidgetComponent extends WidgetComponent implements OnInit { } else { this.displayValue = this.field.value; } + this.initErrorStateMatcher(); + } + + private initErrorStateMatcher(): void { + this.errorStateMatcher = { + isErrorState: (_control: UntypedFormControl | null, _form: FormGroupDirective | NgForm | null): boolean => + !this.field.isValid && this.isTouched() + }; + } + + private updateTranslateParameters(): void { + if (this.field.validationSummary?.isActive()) { + this.translateParameters = this.field.validationSummary.getAttributesAsJsonObj(); + } else { + this.translateParameters = {}; + } + } + + onBlur(): void { + this.markAsTouched(); + this.updateTranslateParameters(); } protected onNumberChange(value: string) { diff --git a/lib/core/src/lib/form/components/widgets/text/text.widget.html b/lib/core/src/lib/form/components/widgets/text/text.widget.html index b580f79e29..6ead4db340 100644 --- a/lib/core/src/lib/form/components/widgets/text/text.widget.html +++ b/lib/core/src/lib/form/components/widgets/text/text.widget.html @@ -8,7 +8,7 @@
- + @if ( (field.name || this.field?.required) && !field.leftLabels) { {{ field.name | translate }}