mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-07-24 17:32:15 +00:00
AAE-23950 Apply reactive forms for date&time and date widgets (#9852)
* AAE-19102 Date should be formatted correctly on the task form considering specified display format * validation fix * rebase * update validation * remove duplicated error widgets * changes after rebase * unit tests update * implement suggestions * test link-adf change * remove link-adf change * fix error for provide value with different format than specified * implement suggestion * fix timezone issue for min/max dates * fix another format issue * exported default date format
This commit is contained in:
@@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges, OnDestroy, HostListener, OnInit } from '@angular/core';
|
||||
import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges, OnDestroy, HostListener, OnInit, ChangeDetectorRef } from '@angular/core';
|
||||
import { Observable, of, forkJoin, Subject, Subscription } from 'rxjs';
|
||||
import { switchMap, takeUntil, map, filter } from 'rxjs/operators';
|
||||
import {
|
||||
@@ -130,7 +130,8 @@ export class FormCloudComponent extends FormBaseComponent implements OnChanges,
|
||||
private dialog: MatDialog,
|
||||
protected visibilityService: WidgetVisibilityService,
|
||||
private readonly displayModeService: DisplayModeService,
|
||||
private spinnerService: FormCloudSpinnerService
|
||||
private spinnerService: FormCloudSpinnerService,
|
||||
private readonly changeDetector: ChangeDetectorRef
|
||||
) {
|
||||
super();
|
||||
|
||||
@@ -421,6 +422,7 @@ export class FormCloudComponent extends FormBaseComponent implements OnChanges,
|
||||
this.displayModeOn.emit(this.displayModeService.findConfiguration(this.displayMode, this.displayModeConfigurations));
|
||||
}
|
||||
|
||||
this.changeDetector.detectChanges();
|
||||
this.formLoaded.emit(form);
|
||||
}
|
||||
|
||||
|
@@ -1,4 +1,4 @@
|
||||
<div class="{{field.className}}" id="data-widget" [class.adf-invalid]="!field.isValid && isTouched()" [class.adf-left-label-input-container]="field.leftLabels">
|
||||
<div class="{{field.className}}" id="data-widget" [class.adf-invalid]="dateInputControl.invalid && dateInputControl.touched" [class.adf-left-label-input-container]="field.leftLabels">
|
||||
<div *ngIf="field.leftLabels">
|
||||
<label class="adf-label adf-left-label" [attr.for]="field.id">{{field.name | translate }} ({{field.dateDisplayFormat}})<span class="adf-asterisk"
|
||||
*ngIf="isRequired()">*</span></label>
|
||||
@@ -7,24 +7,21 @@
|
||||
<mat-form-field class="adf-date-widget" [class.adf-left-label-input-datepicker]="field.leftLabels" [hideRequiredMarker]="true">
|
||||
<label class="adf-label" *ngIf="!field.leftLabels" [attr.for]="field.id">{{field.name | translate }} ({{field.dateDisplayFormat}})<span class="adf-asterisk"
|
||||
*ngIf="isRequired()">*</span></label>
|
||||
<input matInput [matDatepicker]="datePicker"
|
||||
<input matInput
|
||||
[matDatepicker]="datePicker"
|
||||
[id]="field.id"
|
||||
[(ngModel)]="value"
|
||||
[required]="field.required"
|
||||
[formControl]="dateInputControl"
|
||||
[placeholder]="field.placeholder"
|
||||
[min]="minDate"
|
||||
[max]="maxDate"
|
||||
[disabled]="field.readOnly"
|
||||
[title]="field.tooltip"
|
||||
(dateChange)="onDateChanged($event)"
|
||||
(blur)="markAsTouched()">
|
||||
(blur)="updateField()">
|
||||
<mat-datepicker-toggle matSuffix [for]="datePicker" [disabled]="field.readOnly"></mat-datepicker-toggle>
|
||||
<mat-datepicker #datePicker
|
||||
[startAt]="startAt"
|
||||
[disabled]="field.readOnly">
|
||||
</mat-datepicker>
|
||||
</mat-form-field>
|
||||
<error-widget [error]="field.validationSummary"></error-widget>
|
||||
<error-widget *ngIf="isInvalidFieldRequired() && isTouched()" required="{{ 'FORM.FIELD.REQUIRED' | translate }}"></error-widget>
|
||||
<error-widget *ngIf="dateInputControl.invalid && dateInputControl.touched" [error]="field.validationSummary"></error-widget>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -17,7 +17,7 @@
|
||||
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { DateCloudWidgetComponent } from './date-cloud.widget';
|
||||
import { FormFieldModel, FormModel, FormFieldTypes, DateFieldValidator, MinDateFieldValidator, MaxDateFieldValidator } from '@alfresco/adf-core';
|
||||
import { FormFieldModel, FormModel, FormFieldTypes, DEFAULT_DATE_FORMAT } from '@alfresco/adf-core';
|
||||
import { ProcessServiceCloudTestingModule } from '../../../../testing/process-service-cloud.testing.module';
|
||||
import { DateAdapter } from '@angular/material/core';
|
||||
import { isEqual, subDays, addDays } from 'date-fns';
|
||||
@@ -35,7 +35,6 @@ describe('DateWidgetComponent', () => {
|
||||
});
|
||||
|
||||
form = new FormModel();
|
||||
form.fieldValidators = [new DateFieldValidator(), new MinDateFieldValidator(), new MaxDateFieldValidator()];
|
||||
|
||||
fixture = TestBed.createComponent(DateCloudWidgetComponent);
|
||||
adapter = fixture.debugElement.injector.get(DateAdapter);
|
||||
@@ -52,9 +51,9 @@ describe('DateWidgetComponent', () => {
|
||||
minValue
|
||||
});
|
||||
|
||||
widget.ngOnInit();
|
||||
fixture.detectChanges();
|
||||
|
||||
const expected = adapter.parse(minValue, widget.DATE_FORMAT);
|
||||
const expected = adapter.parse(minValue, DEFAULT_DATE_FORMAT);
|
||||
expect(isEqual(widget.minDate, expected)).toBeTrue();
|
||||
});
|
||||
|
||||
@@ -77,9 +76,9 @@ describe('DateWidgetComponent', () => {
|
||||
type: FormFieldTypes.DATE,
|
||||
maxValue
|
||||
});
|
||||
widget.ngOnInit();
|
||||
fixture.detectChanges();
|
||||
|
||||
const expected = adapter.parse(maxValue, widget.DATE_FORMAT);
|
||||
const expected = adapter.parse(maxValue, DEFAULT_DATE_FORMAT);
|
||||
expect(isEqual(widget.maxDate, expected)).toBeTrue();
|
||||
});
|
||||
|
||||
@@ -95,7 +94,10 @@ describe('DateWidgetComponent', () => {
|
||||
});
|
||||
|
||||
widget.field = field;
|
||||
widget.onDateChanged({ value: adapter.today() } as any);
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
widget.dateInputControl.setValue(new Date('9999-9-9'));
|
||||
|
||||
expect(widget.onFieldChanged).toHaveBeenCalledWith(field);
|
||||
});
|
||||
@@ -106,17 +108,15 @@ describe('DateWidgetComponent', () => {
|
||||
TestBed.resetTestingModule();
|
||||
});
|
||||
|
||||
it('should show visible date widget', async () => {
|
||||
it('should show visible date widget', () => {
|
||||
widget.field = new FormFieldModel(form, {
|
||||
id: 'date-field-id',
|
||||
name: 'date-name',
|
||||
// always stored as dd-MM-yyyy
|
||||
value: '9999-9-9',
|
||||
type: FormFieldTypes.DATE
|
||||
});
|
||||
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
|
||||
const dateElement = element.querySelector<HTMLInputElement>('#date-field-id');
|
||||
expect(dateElement).not.toBeNull();
|
||||
@@ -128,10 +128,9 @@ describe('DateWidgetComponent', () => {
|
||||
widget.field = new FormFieldModel(form, {
|
||||
id: 'date-field-id',
|
||||
name: 'date-name',
|
||||
// always stored as dd-MM-yyyy
|
||||
value: '30-12-9999',
|
||||
value: new Date('12-30-9999'),
|
||||
type: FormFieldTypes.DATE,
|
||||
dateDisplayFormat: 'YYYY-DD-MM'
|
||||
dateDisplayFormat: 'yyyy-dd-MM'
|
||||
});
|
||||
|
||||
fixture.detectChanges();
|
||||
@@ -141,31 +140,29 @@ describe('DateWidgetComponent', () => {
|
||||
expect(dateElement.value).toContain('9999-30-12');
|
||||
});
|
||||
|
||||
it('should disable date button when is readonly', async () => {
|
||||
it('should disable date button when is readonly', () => {
|
||||
widget.field = new FormFieldModel(form, {
|
||||
id: 'date-field-id',
|
||||
name: 'date-name',
|
||||
value: '9999-9-9',
|
||||
type: FormFieldTypes.DATE,
|
||||
readOnly: 'false'
|
||||
readOnly: false
|
||||
});
|
||||
widget.field.isVisible = true;
|
||||
widget.field.readOnly = false;
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
|
||||
let dateButton = element.querySelector<HTMLButtonElement>('button');
|
||||
expect(dateButton.disabled).toBeFalsy();
|
||||
|
||||
widget.field.readOnly = true;
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
|
||||
dateButton = element.querySelector<HTMLButtonElement>('button');
|
||||
expect(dateButton.disabled).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should set isValid to false when the value is not a correct date value', async () => {
|
||||
it('should set isValid to false when the value is not a correct date value', () => {
|
||||
widget.field = new FormFieldModel(new FormModel(), {
|
||||
id: 'date-field-id',
|
||||
name: 'date-name',
|
||||
@@ -177,42 +174,43 @@ describe('DateWidgetComponent', () => {
|
||||
widget.field.readOnly = false;
|
||||
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
|
||||
widget.dateInputControl.setValue(new Date('invalid date'));
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(widget.field.isValid).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
it('should display always the json value', async () => {
|
||||
it('should display always the json value', () => {
|
||||
const field = new FormFieldModel(form, {
|
||||
id: 'date-field-id',
|
||||
name: 'date-name',
|
||||
// always stored as dd-MM-yyyy
|
||||
value: '30-12-9999',
|
||||
value: new Date('12-30-9999'),
|
||||
type: FormFieldTypes.DATE,
|
||||
readOnly: 'false',
|
||||
dateDisplayFormat: 'MM-DD-YYYY'
|
||||
readOnly: false,
|
||||
dateDisplayFormat: 'MM-dd-yyyy'
|
||||
});
|
||||
widget.field = field;
|
||||
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
|
||||
const dateElement = element.querySelector<HTMLInputElement>('#date-field-id');
|
||||
expect(dateElement).toBeDefined();
|
||||
expect(dateElement.value).toContain('12-30-9999');
|
||||
|
||||
widget.field.value = '03-02-2020';
|
||||
dateElement.value = '03-02-2020';
|
||||
dateElement.dispatchEvent(new Event('input'));
|
||||
|
||||
fixture.componentInstance.ngOnInit();
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
|
||||
expect(dateElement.value).toContain('02-03-2020');
|
||||
expect(dateElement.value).toContain('03-02-2020');
|
||||
});
|
||||
|
||||
describe('when form model has left labels', () => {
|
||||
it('should have left labels classes on leftLabels true', async () => {
|
||||
it('should have left labels classes on leftLabels true', () => {
|
||||
widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id', leftLabels: true }), {
|
||||
id: 'date-id',
|
||||
name: 'date-name',
|
||||
@@ -223,7 +221,6 @@ describe('DateWidgetComponent', () => {
|
||||
});
|
||||
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
|
||||
const widgetContainer = element.querySelector('.adf-left-label-input-container');
|
||||
expect(widgetContainer).not.toBeNull();
|
||||
@@ -235,7 +232,7 @@ describe('DateWidgetComponent', () => {
|
||||
expect(adfLeftLabel).not.toBeNull();
|
||||
});
|
||||
|
||||
it('should not have left labels classes on leftLabels false', async () => {
|
||||
it('should not have left labels classes on leftLabels false', () => {
|
||||
widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id', leftLabels: false }), {
|
||||
id: 'date-id',
|
||||
name: 'date-name',
|
||||
@@ -246,7 +243,6 @@ describe('DateWidgetComponent', () => {
|
||||
});
|
||||
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
|
||||
const widgetContainer = element.querySelector('.adf-left-label-input-container');
|
||||
expect(widgetContainer).toBeNull();
|
||||
@@ -258,7 +254,7 @@ describe('DateWidgetComponent', () => {
|
||||
expect(adfLeftLabel).toBeNull();
|
||||
});
|
||||
|
||||
it('should not have left labels classes on leftLabels not present', async () => {
|
||||
it('should not have left labels classes on leftLabels not present', () => {
|
||||
widget.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id' }), {
|
||||
id: 'date-id',
|
||||
name: 'date-name',
|
||||
@@ -269,7 +265,6 @@ describe('DateWidgetComponent', () => {
|
||||
});
|
||||
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
|
||||
const widgetContainer = element.querySelector('.adf-left-label-input-container');
|
||||
expect(widgetContainer).toBeNull();
|
||||
@@ -291,7 +286,7 @@ describe('DateWidgetComponent', () => {
|
||||
});
|
||||
|
||||
describe('Minimum date range value and date', () => {
|
||||
it('should set minimum date range date to today if minimum date range value is 0', async () => {
|
||||
it('should set minimum date range date to today if minimum date range value is 0', () => {
|
||||
widget.field = new FormFieldModel(form, {
|
||||
type: FormFieldTypes.DATE,
|
||||
dynamicDateRangeSelection: true,
|
||||
@@ -300,7 +295,6 @@ describe('DateWidgetComponent', () => {
|
||||
});
|
||||
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
|
||||
const expectedMinDate = adapter.today();
|
||||
|
||||
@@ -308,7 +302,7 @@ describe('DateWidgetComponent', () => {
|
||||
expect(widget.field.minValue).toBe(todayString);
|
||||
});
|
||||
|
||||
it('should set minimum date range date to null if minimum date range value is null', async () => {
|
||||
it('should set minimum date range date to null if minimum date range value is null', () => {
|
||||
widget.field = new FormFieldModel(form, {
|
||||
type: FormFieldTypes.DATE,
|
||||
dynamicDateRangeSelection: true,
|
||||
@@ -317,13 +311,12 @@ describe('DateWidgetComponent', () => {
|
||||
});
|
||||
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
|
||||
expect(widget.minDate).toBeNull();
|
||||
expect(widget.field.minValue).toBeNull();
|
||||
});
|
||||
|
||||
it('should set minimum date range date to today minus abs(minDateRangeValue) if minimum date range value is negative', async () => {
|
||||
it('should set minimum date range date to today minus abs(minDateRangeValue) if minimum date range value is negative', () => {
|
||||
widget.field = new FormFieldModel(form, {
|
||||
type: FormFieldTypes.DATE,
|
||||
dynamicDateRangeSelection: true,
|
||||
@@ -332,7 +325,6 @@ describe('DateWidgetComponent', () => {
|
||||
});
|
||||
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
|
||||
const expectedMinDate = subDays(adapter.today(), 2);
|
||||
|
||||
@@ -340,7 +332,7 @@ describe('DateWidgetComponent', () => {
|
||||
expect(widget.field.minValue).toBe('20-02-2022');
|
||||
});
|
||||
|
||||
it('should set minimum date range date to today plus minDateRangeValue if minimum date range value is positive', async () => {
|
||||
it('should set minimum date range date to today plus minDateRangeValue if minimum date range value is positive', () => {
|
||||
widget.field = new FormFieldModel(form, {
|
||||
type: FormFieldTypes.DATE,
|
||||
dynamicDateRangeSelection: true,
|
||||
@@ -349,7 +341,6 @@ describe('DateWidgetComponent', () => {
|
||||
});
|
||||
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
|
||||
const expectedMinDate = addDays(adapter.today(), 2);
|
||||
|
||||
@@ -359,7 +350,7 @@ describe('DateWidgetComponent', () => {
|
||||
});
|
||||
|
||||
describe('Maximum date range value and date', () => {
|
||||
it('should set maximum date range date to today if maximum date range value is 0', async () => {
|
||||
it('should set maximum date range date to today if maximum date range value is 0', () => {
|
||||
widget.field = new FormFieldModel(form, {
|
||||
type: FormFieldTypes.DATE,
|
||||
dynamicDateRangeSelection: true,
|
||||
@@ -368,7 +359,6 @@ describe('DateWidgetComponent', () => {
|
||||
});
|
||||
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
|
||||
const expectedMaxDate = adapter.today();
|
||||
|
||||
@@ -376,7 +366,7 @@ describe('DateWidgetComponent', () => {
|
||||
expect(widget.field.maxValue).toBe(todayString);
|
||||
});
|
||||
|
||||
it('should set maximum date range date to null if maximum date range value is null', async () => {
|
||||
it('should set maximum date range date to null if maximum date range value is null', () => {
|
||||
widget.field = new FormFieldModel(form, {
|
||||
type: FormFieldTypes.DATE,
|
||||
dynamicDateRangeSelection: true,
|
||||
@@ -385,13 +375,12 @@ describe('DateWidgetComponent', () => {
|
||||
});
|
||||
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
|
||||
expect(widget.maxDate).toBeNull();
|
||||
expect(widget.field.maxValue).toBeNull();
|
||||
});
|
||||
|
||||
it('should set maximum date range date to today minus abs(maxDateRangeValue) if maximum date range value is negative', async () => {
|
||||
it('should set maximum date range date to today minus abs(maxDateRangeValue) if maximum date range value is negative', () => {
|
||||
widget.field = new FormFieldModel(form, {
|
||||
type: FormFieldTypes.DATE,
|
||||
dynamicDateRangeSelection: true,
|
||||
@@ -400,7 +389,6 @@ describe('DateWidgetComponent', () => {
|
||||
});
|
||||
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
|
||||
const expectedMaxDate = subDays(adapter.today(), 2);
|
||||
|
||||
@@ -408,7 +396,7 @@ describe('DateWidgetComponent', () => {
|
||||
expect(widget.field.maxValue).toBe('20-02-2022');
|
||||
});
|
||||
|
||||
it('should set maximum date range date to today plus maxDateRangeValue if maximum date range value is positive', async () => {
|
||||
it('should set maximum date range date to today plus maxDateRangeValue if maximum date range value is positive', () => {
|
||||
widget.field = new FormFieldModel(form, {
|
||||
type: FormFieldTypes.DATE,
|
||||
dynamicDateRangeSelection: true,
|
||||
@@ -417,7 +405,6 @@ describe('DateWidgetComponent', () => {
|
||||
});
|
||||
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
|
||||
const expectedMaxDate = addDays(adapter.today(), 2);
|
||||
|
||||
@@ -435,9 +422,8 @@ describe('DateWidgetComponent', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('should be able to display label with asterisk', async () => {
|
||||
it('should be able to display label with asterisk', () => {
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
|
||||
const asterisk: HTMLElement = element.querySelector('.adf-asterisk');
|
||||
|
||||
@@ -445,9 +431,8 @@ describe('DateWidgetComponent', () => {
|
||||
expect(asterisk.textContent).toEqual('*');
|
||||
});
|
||||
|
||||
it('should be invalid after user interaction without typing', async () => {
|
||||
it('should be invalid after user interaction without typing', () => {
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
|
||||
expect(element.querySelector('.adf-invalid')).toBeFalsy();
|
||||
|
||||
@@ -455,7 +440,6 @@ describe('DateWidgetComponent', () => {
|
||||
dateCloudInput.dispatchEvent(new Event('blur'));
|
||||
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
|
||||
expect(element.querySelector('.adf-invalid')).toBeTruthy();
|
||||
});
|
||||
|
@@ -17,15 +17,42 @@
|
||||
|
||||
/* eslint-disable @angular-eslint/component-selector */
|
||||
|
||||
import { Component, OnInit, ViewEncapsulation, OnDestroy, Input } from '@angular/core';
|
||||
import { Component, OnInit, ViewEncapsulation, OnDestroy, inject } from '@angular/core';
|
||||
import { DateAdapter, MAT_DATE_FORMATS } from '@angular/material/core';
|
||||
import { Subject } from 'rxjs';
|
||||
import { WidgetComponent, FormService, AdfDateFnsAdapter, DateFnsUtils, ADF_DATE_FORMATS } from '@alfresco/adf-core';
|
||||
import { MatDatepickerInputEvent } from '@angular/material/datepicker';
|
||||
import { addDays } from 'date-fns';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
import {
|
||||
WidgetComponent,
|
||||
FormService,
|
||||
AdfDateFnsAdapter,
|
||||
DateFnsUtils,
|
||||
ADF_DATE_FORMATS,
|
||||
ErrorWidgetComponent,
|
||||
ErrorMessageModel,
|
||||
DEFAULT_DATE_FORMAT
|
||||
} from '@alfresco/adf-core';
|
||||
import { MatDatepickerModule } from '@angular/material/datepicker';
|
||||
import { addDays, parseISO } from 'date-fns';
|
||||
import { FormControl, ReactiveFormsModule, ValidationErrors, Validators } from '@angular/forms';
|
||||
import { NgIf } from '@angular/common';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
|
||||
@Component({
|
||||
selector: 'date-widget',
|
||||
standalone: true,
|
||||
imports: [
|
||||
NgIf,
|
||||
TranslateModule,
|
||||
MatFormFieldModule,
|
||||
MatInputModule,
|
||||
MatDatepickerModule,
|
||||
MatTooltipModule,
|
||||
ReactiveFormsModule,
|
||||
ErrorWidgetComponent
|
||||
],
|
||||
providers: [
|
||||
{ provide: MAT_DATE_FORMATS, useValue: ADF_DATE_FORMATS },
|
||||
{ provide: DateAdapter, useClass: AdfDateFnsAdapter }
|
||||
@@ -47,80 +74,143 @@ import { addDays } from 'date-fns';
|
||||
})
|
||||
export class DateCloudWidgetComponent extends WidgetComponent implements OnInit, OnDestroy {
|
||||
typeId = 'DateCloudWidgetComponent';
|
||||
readonly DATE_FORMAT = 'dd-MM-yyyy';
|
||||
|
||||
minDate: Date = null;
|
||||
maxDate: Date = null;
|
||||
startAt: Date = null;
|
||||
|
||||
/**
|
||||
* Current date value.
|
||||
* The value is always stored in the format `dd-MM-yyyy`,
|
||||
* but displayed in the UI component using `dateDisplayFormat`
|
||||
*/
|
||||
@Input()
|
||||
value: any = null;
|
||||
dateInputControl: FormControl<Date> = new FormControl<Date>(null);
|
||||
|
||||
private onDestroy$ = new Subject<boolean>();
|
||||
private onDestroy$ = new Subject<void>();
|
||||
|
||||
constructor(public formService: FormService, private dateAdapter: DateAdapter<Date>) {
|
||||
super(formService);
|
||||
public readonly formService = inject(FormService);
|
||||
private readonly dateAdapter = inject(DateAdapter);
|
||||
|
||||
ngOnInit(): void {
|
||||
this.patchFormControl();
|
||||
this.initDateAdapter();
|
||||
this.initRangeSelection();
|
||||
this.initStartAt();
|
||||
this.subscribeToDateChanges();
|
||||
this.updateField();
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
if (this.field.dateDisplayFormat) {
|
||||
updateField(): void {
|
||||
this.validateField();
|
||||
this.onFieldChanged(this.field);
|
||||
}
|
||||
|
||||
private patchFormControl(): void {
|
||||
this.dateInputControl.setValue(this.field.value, { emitEvent: false });
|
||||
this.dateInputControl.setValidators(this.isRequired() ? [Validators.required] : []);
|
||||
if (this.field?.readOnly || this.readOnly) {
|
||||
this.dateInputControl.disable({ emitEvent: false });
|
||||
}
|
||||
|
||||
this.dateInputControl.updateValueAndValidity({ emitEvent: false });
|
||||
}
|
||||
|
||||
private subscribeToDateChanges(): void {
|
||||
this.dateInputControl.valueChanges.pipe(takeUntil(this.onDestroy$)).subscribe((newDate: Date) => {
|
||||
this.field.value = newDate;
|
||||
this.updateField();
|
||||
});
|
||||
}
|
||||
|
||||
private validateField(): void {
|
||||
if (this.dateInputControl.invalid) {
|
||||
this.handleErrors(this.dateInputControl.errors);
|
||||
this.field.markAsInvalid();
|
||||
} else {
|
||||
this.resetErrors();
|
||||
this.field.markAsValid();
|
||||
}
|
||||
}
|
||||
|
||||
private handleErrors(errors: ValidationErrors): void {
|
||||
const errorAttributes = new Map<string, string>();
|
||||
switch (true) {
|
||||
case !!errors.matDatepickerParse:
|
||||
this.updateValidationSummary(this.field.dateDisplayFormat || this.field.defaultDateTimeFormat);
|
||||
break;
|
||||
case !!errors.required:
|
||||
this.updateValidationSummary('FORM.FIELD.REQUIRED');
|
||||
break;
|
||||
case !!errors.matDatepickerMin: {
|
||||
const minValue = DateFnsUtils.formatDate(errors.matDatepickerMin.min, this.field.dateDisplayFormat).toLocaleUpperCase();
|
||||
errorAttributes.set('minValue', minValue);
|
||||
this.updateValidationSummary('FORM.FIELD.VALIDATOR.NOT_LESS_THAN', errorAttributes);
|
||||
break;
|
||||
}
|
||||
case !!errors.matDatepickerMax: {
|
||||
const maxValue = DateFnsUtils.formatDate(errors.matDatepickerMax.max, this.field.dateDisplayFormat).toLocaleUpperCase();
|
||||
errorAttributes.set('maxValue', maxValue);
|
||||
this.updateValidationSummary('FORM.FIELD.VALIDATOR.NOT_GREATER_THAN', errorAttributes);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private updateValidationSummary(message: string, attributes?: Map<string, string>): void {
|
||||
this.field.validationSummary = new ErrorMessageModel({ message, attributes });
|
||||
}
|
||||
|
||||
private resetErrors(): void {
|
||||
this.updateValidationSummary('');
|
||||
}
|
||||
|
||||
private initDateAdapter(): void {
|
||||
if (this.field?.dateDisplayFormat) {
|
||||
const adapter = this.dateAdapter as AdfDateFnsAdapter;
|
||||
adapter.displayFormat = this.field.dateDisplayFormat;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.field) {
|
||||
if (this.field.dynamicDateRangeSelection) {
|
||||
if (this.field.minDateRangeValue === null) {
|
||||
this.minDate = null;
|
||||
this.field.minValue = null;
|
||||
} else {
|
||||
this.minDate = addDays(this.dateAdapter.today(), this.field.minDateRangeValue);
|
||||
this.field.minValue = DateFnsUtils.formatDate(this.minDate, this.DATE_FORMAT);
|
||||
}
|
||||
if (this.field.maxDateRangeValue === null) {
|
||||
this.maxDate = null;
|
||||
this.field.maxValue = null;
|
||||
} else {
|
||||
this.maxDate = addDays(this.dateAdapter.today(), this.field.maxDateRangeValue);
|
||||
this.field.maxValue = DateFnsUtils.formatDate(this.maxDate, this.DATE_FORMAT);
|
||||
}
|
||||
} else {
|
||||
if (this.field.minValue) {
|
||||
this.minDate = this.dateAdapter.parse(this.field.minValue, this.DATE_FORMAT);
|
||||
}
|
||||
|
||||
if (this.field.maxValue) {
|
||||
this.maxDate = this.dateAdapter.parse(this.field.maxValue, this.DATE_FORMAT);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.field.value) {
|
||||
this.startAt = this.dateAdapter.parse(this.field.value, this.DATE_FORMAT);
|
||||
this.value = this.dateAdapter.parse(this.field.value, this.DATE_FORMAT);
|
||||
}
|
||||
private initStartAt(): void {
|
||||
if (this.field?.value) {
|
||||
this.startAt = this.dateAdapter.parse(this.field.value, DEFAULT_DATE_FORMAT);
|
||||
}
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.onDestroy$.next(true);
|
||||
private initRangeSelection(): void {
|
||||
if (this.field?.dynamicDateRangeSelection) {
|
||||
this.setDynamicRangeSelection();
|
||||
} else {
|
||||
this.setStaticRangeSelection();
|
||||
}
|
||||
}
|
||||
|
||||
private setDynamicRangeSelection(): void {
|
||||
if (this.field.minDateRangeValue === null) {
|
||||
this.minDate = null;
|
||||
this.field.minValue = null;
|
||||
} else {
|
||||
this.minDate = addDays(this.dateAdapter.today(), this.field.minDateRangeValue);
|
||||
this.field.minValue = DateFnsUtils.formatDate(this.minDate, DEFAULT_DATE_FORMAT);
|
||||
}
|
||||
if (this.field.maxDateRangeValue === null) {
|
||||
this.maxDate = null;
|
||||
this.field.maxValue = null;
|
||||
} else {
|
||||
this.maxDate = addDays(this.dateAdapter.today(), this.field.maxDateRangeValue);
|
||||
this.field.maxValue = DateFnsUtils.formatDate(this.maxDate, DEFAULT_DATE_FORMAT);
|
||||
}
|
||||
}
|
||||
|
||||
private setStaticRangeSelection(): void {
|
||||
if (this.field?.minValue) {
|
||||
this.minDate = parseISO(this.field.minValue);
|
||||
}
|
||||
|
||||
if (this.field?.maxValue) {
|
||||
this.maxDate = parseISO(this.field.maxValue);
|
||||
}
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.onDestroy$.next();
|
||||
this.onDestroy$.complete();
|
||||
}
|
||||
|
||||
onDateChanged(event: MatDatepickerInputEvent<Date>) {
|
||||
const value = event.value;
|
||||
const input = event.targetElement as HTMLInputElement;
|
||||
|
||||
if (value) {
|
||||
this.field.value = this.dateAdapter.format(value, this.DATE_FORMAT);
|
||||
} else {
|
||||
this.field.value = input.value;
|
||||
}
|
||||
|
||||
this.onFieldChanged(this.field);
|
||||
}
|
||||
}
|
||||
|
@@ -29,8 +29,6 @@ import {
|
||||
CONTENT_UPLOAD_DIRECTIVES,
|
||||
ContentNodeSelectorModule
|
||||
} from '@alfresco/adf-content-services';
|
||||
|
||||
import { DateCloudWidgetComponent } from './components/widgets/date/date-cloud.widget';
|
||||
import { DropdownCloudWidgetComponent } from './components/widgets/dropdown/dropdown-cloud.widget';
|
||||
import { GroupCloudWidgetComponent } from './components/widgets/group/group-cloud.widget';
|
||||
import { PeopleCloudWidgetComponent } from './components/widgets/people/people-cloud.widget';
|
||||
@@ -78,7 +76,6 @@ import { FormCloudSpinnerService } from './services/spinner/form-cloud-spinner.s
|
||||
DropdownCloudWidgetComponent,
|
||||
RadioButtonsCloudWidgetComponent,
|
||||
AttachFileCloudWidgetComponent,
|
||||
DateCloudWidgetComponent,
|
||||
PeopleCloudWidgetComponent,
|
||||
GroupCloudWidgetComponent,
|
||||
PropertiesViewerWrapperComponent,
|
||||
@@ -96,7 +93,6 @@ import { FormCloudSpinnerService } from './services/spinner/form-cloud-spinner.s
|
||||
DropdownCloudWidgetComponent,
|
||||
RadioButtonsCloudWidgetComponent,
|
||||
AttachFileCloudWidgetComponent,
|
||||
DateCloudWidgetComponent,
|
||||
PeopleCloudWidgetComponent,
|
||||
GroupCloudWidgetComponent,
|
||||
PropertiesViewerWidgetComponent,
|
||||
|
Reference in New Issue
Block a user