diff --git a/projects/dsp-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html b/projects/dsp-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html index 29f24c58f..57f2c59ac 100644 --- a/projects/dsp-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html +++ b/projects/dsp-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html @@ -38,12 +38,12 @@ Start date is required - - In a period, start and end date must use the same + + In a period, start and end dates are required and must use the same calendar - - In a period, start must be before end + + In a period, start must be before end diff --git a/projects/dsp-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts b/projects/dsp-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts index 262b280f8..5e6c215a4 100644 --- a/projects/dsp-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts +++ b/projects/dsp-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts @@ -2,7 +2,7 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { DateInputComponent } from './date-input.component'; import { Component, OnInit, ViewChild } from '@angular/core'; -import { FormBuilder, FormGroup, ReactiveFormsModule } from '@angular/forms'; +import { FormBuilder, FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms'; import { KnoraDate, KnoraPeriod } from '@dasch-swiss/dsp-js'; import { JDNDatepickerDirective } from '../../jdn-datepicker-directive/jdndatepicker.directive'; import { MatFormFieldModule } from '@angular/material/form-field'; @@ -46,6 +46,35 @@ class TestHostComponent implements OnInit { } } +/** + * Test host component to simulate parent component. + */ +@Component({ + template: ` +
+ + + +
` +}) +class NoValueRequiredTestHostComponent implements OnInit { + + @ViewChild('dateInput') dateInputComponent: DateInputComponent; + + form: FormGroup; + + constructor(private _fb: FormBuilder) { + } + + ngOnInit(): void { + + this.form = this._fb.group({ + date: new FormControl(null) + }); + + } +} + describe('DateInputComponent', () => { let testHostComponent: TestHostComponent; let testHostFixture: ComponentFixture; @@ -261,4 +290,52 @@ describe('DateInputComponent', () => { }); + it('should mark the form\'s validity correctly', () => { + expect(testHostComponent.dateInputComponent.valueRequiredValidator).toBe(true); + expect(testHostComponent.dateInputComponent.form.valid).toBe(true); + + testHostComponent.dateInputComponent.startDateControl.setValue(null); + + testHostComponent.dateInputComponent._handleInput(); + + expect(testHostComponent.dateInputComponent.form.valid).toBe(false); + }); + +}); + +describe('NoValueRequiredTestHostComponent', () => { + let testHostComponent: NoValueRequiredTestHostComponent; + let testHostFixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ + ReactiveFormsModule, + MatFormFieldModule, + MatInputModule, + MatDatepickerModule, + MatCheckboxModule, + MatJDNConvertibleCalendarDateAdapterModule, + BrowserAnimationsModule + ], + declarations: [DateInputComponent, NoValueRequiredTestHostComponent, JDNDatepickerDirective] + }) + .compileComponents(); + })); + + beforeEach(() => { + testHostFixture = TestBed.createComponent(NoValueRequiredTestHostComponent); + testHostComponent = testHostFixture.componentInstance; + testHostFixture.detectChanges(); + + expect(testHostComponent).toBeTruthy(); + }); + + it('should recieve the propagated valueRequiredValidator from the parent component', () => { + expect(testHostComponent.dateInputComponent.valueRequiredValidator).toBe(false); + }); + + it('should mark the form\'s validity correctly', () => { + expect(testHostComponent.dateInputComponent.form.valid).toBe(true); + }); }); diff --git a/projects/dsp-ui/src/lib/viewer/values/date-value/date-input/date-input.component.ts b/projects/dsp-ui/src/lib/viewer/values/date-value/date-input/date-input.component.ts index 16c6c1f5a..b07f43ed5 100644 --- a/projects/dsp-ui/src/lib/viewer/values/date-value/date-input/date-input.component.ts +++ b/projects/dsp-ui/src/lib/viewer/values/date-value/date-input/date-input.component.ts @@ -1,6 +1,6 @@ import { FocusMonitor } from '@angular/cdk/a11y'; import { coerceBooleanProperty } from '@angular/cdk/coercion'; -import { Component, DoCheck, ElementRef, HostBinding, Input, OnDestroy, Optional, Self } from '@angular/core'; +import { Component, DoCheck, ElementRef, HostBinding, Input, OnDestroy, OnInit, Optional, Self } from '@angular/core'; import { AbstractControl, ControlValueAccessor, @@ -93,7 +93,7 @@ const _MatInputMixinBase: CanUpdateErrorStateCtor & typeof MatInputBase = styleUrls: ['./date-input.component.scss'], providers: [{ provide: MatFormFieldControl, useExisting: DateInputComponent }] }) -export class DateInputComponent extends _MatInputMixinBase implements ControlValueAccessor, MatFormFieldControl, DoCheck, CanUpdateErrorState, OnDestroy { +export class DateInputComponent extends _MatInputMixinBase implements ControlValueAccessor, MatFormFieldControl, DoCheck, CanUpdateErrorState, OnDestroy, OnInit { static nextId = 0; @@ -110,6 +110,8 @@ export class DateInputComponent extends _MatInputMixinBase implements ControlVal endDateControl: FormControl; isPeriodControl: FormControl; + @Input() valueRequiredValidator = true; + onChange = (_: any) => { }; onTouched = () => { @@ -267,15 +269,7 @@ export class DateInputComponent extends _MatInputMixinBase implements ControlVal this.endDateControl = new FormControl(null); this.isPeriodControl = new FormControl(null); - this.startDateControl - = new FormControl( - null, - [ - Validators.required, - sameCalendarValidator(this.isPeriodControl, this.endDateControl), - periodStartEndValidator(this.isPeriodControl, this.endDateControl) - ] - ); + this.startDateControl = new FormControl(null); this.form = fb.group({ dateStart: this.startDateControl, @@ -283,7 +277,6 @@ export class DateInputComponent extends _MatInputMixinBase implements ControlVal isPeriod: this.isPeriodControl }); - _fm.monitor(_elRef.nativeElement, true).subscribe(origin => { this.focused = !!origin; this.stateChanges.next(); @@ -294,6 +287,23 @@ export class DateInputComponent extends _MatInputMixinBase implements ControlVal } } + ngOnInit() { + if (this.valueRequiredValidator) { + this.startDateControl.setValidators([ + Validators.required, + sameCalendarValidator(this.isPeriodControl, this.endDateControl), + periodStartEndValidator(this.isPeriodControl, this.endDateControl) + ]); + } else { + this.startDateControl.setValidators([ + sameCalendarValidator(this.isPeriodControl, this.endDateControl), + periodStartEndValidator(this.isPeriodControl, this.endDateControl) + ]); + } + + this.startDateControl.updateValueAndValidity(); + } + ngDoCheck() { if (this.ngControl) { this.updateErrorState(); diff --git a/projects/dsp-ui/src/lib/viewer/values/date-value/date-value.component.html b/projects/dsp-ui/src/lib/viewer/values/date-value/date-value.component.html index 6ac9f8e35..dcd96c734 100644 --- a/projects/dsp-ui/src/lib/viewer/values/date-value/date-value.component.html +++ b/projects/dsp-ui/src/lib/viewer/values/date-value/date-value.component.html @@ -34,7 +34,7 @@ - + New value must be different than the current value. diff --git a/projects/dsp-ui/src/lib/viewer/values/date-value/date-value.component.spec.ts b/projects/dsp-ui/src/lib/viewer/values/date-value/date-value.component.spec.ts index 642b4881f..adad2580c 100644 --- a/projects/dsp-ui/src/lib/viewer/values/date-value/date-value.component.spec.ts +++ b/projects/dsp-ui/src/lib/viewer/values/date-value/date-value.component.spec.ts @@ -36,6 +36,7 @@ class TestDateInputComponent implements ControlValueAccessor, MatFormFieldContro @Input() required: boolean; @Input() shouldLabelFloat: boolean; @Input() errorStateMatcher: ErrorStateMatcher; + @Input() valueRequiredValidator = true; errorState = false; focused = false; @@ -116,6 +117,26 @@ class TestHostCreateValueComponent implements OnInit { } } +/** + * Test host component to simulate parent component. + */ +@Component({ + template: ` + ` + }) + class TestHostCreateValueNoValueRequiredComponent implements OnInit { + + @ViewChild('inputVal') inputValueComponent: DateValueComponent; + + mode: 'read' | 'update' | 'create' | 'search'; + + ngOnInit() { + + this.mode = 'create'; + + } + } + describe('DateValueComponent', () => { beforeEach(async(() => { @@ -130,6 +151,7 @@ describe('DateValueComponent', () => { TestDateInputComponent, TestHostDisplayValueComponent, TestHostCreateValueComponent, + TestHostCreateValueNoValueRequiredComponent, KnoraDatePipe ] }) @@ -611,5 +633,29 @@ describe('DateValueComponent', () => { }); + describe('create a date value no required value', () => { + + let testHostComponent: TestHostCreateValueNoValueRequiredComponent; + let testHostFixture: ComponentFixture; + + beforeEach(() => { + testHostFixture = TestBed.createComponent(TestHostCreateValueNoValueRequiredComponent); + testHostComponent = testHostFixture.componentInstance; + testHostFixture.detectChanges(); + + expect(testHostComponent).toBeTruthy(); + expect(testHostComponent.inputValueComponent).toBeTruthy(); + }); + + it('should not create an empty value', () => { + expect(testHostComponent.inputValueComponent.getNewValue()).toBe(false); + expect(testHostComponent.inputValueComponent.form.valid).toBe(true); + }); + + it('should propagate valueRequiredValidator to child component', () => { + expect(testHostComponent.inputValueComponent.valueRequiredValidator).toBe(false); + }); + + }); }); diff --git a/projects/dsp-ui/src/lib/viewer/values/int-value/int-value.component.spec.ts b/projects/dsp-ui/src/lib/viewer/values/int-value/int-value.component.spec.ts index bd9813062..b4e6a9376 100644 --- a/projects/dsp-ui/src/lib/viewer/values/int-value/int-value.component.spec.ts +++ b/projects/dsp-ui/src/lib/viewer/values/int-value/int-value.component.spec.ts @@ -335,8 +335,8 @@ describe('IntValueComponent', () => { }); describe('create value no required value', () => { - let testHostComponent: TestHostCreateValueComponent; - let testHostFixture: ComponentFixture; + let testHostComponent: TestHostCreateValueNoValueRequiredComponent; + let testHostFixture: ComponentFixture; beforeEach(async () => { testHostFixture = TestBed.createComponent(TestHostCreateValueNoValueRequiredComponent);