Skip to content

Commit

Permalink
feat(components/datetime)!: remove deprecated required inputs and upd…
Browse files Browse the repository at this point in the history
…ate error validation (#2654)
  • Loading branch information
Blackbaud-SandhyaRajasabeson committed Aug 28, 2024
1 parent 8af1501 commit 052ea91
Show file tree
Hide file tree
Showing 11 changed files with 130 additions and 119 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,8 @@
stacked="true"
[calculatorIds]="calculatorIds"
[dateFormat]="dateFormat"
[endDateRequired]="endDateRequired"
helpKey="helpKey.html"
[hintText]="hintText"
[startDateRequired]="startDateRequired"
/>

<button class="sky-btn sky-btn-default" type="submit">Submit</button>
Expand Down Expand Up @@ -37,12 +35,6 @@ <h3>Statuses</h3>
<button type="button" (click)="toggleDisabled()">Toggle disabled</button>
<button type="button" (click)="toggleHintText()">Toggle hint text</button>
<button type="button" (click)="toggleRequired()">Toggle required</button>
<button type="button" (click)="toggleStartDateRequired()">
Toggle start date required
</button>
<button type="button" (click)="toggleEndDateRequired()">
Toggle end date required
</button>

<button type="button" (click)="changeDateFormat()">Change date format</button>
<button type="button" (click)="changeLocale()">Change locale</button>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,7 @@ import { LocaleProvider } from './locale-provider';
export class DateRangePickerComponent {
protected calculatorIds: SkyDateRangeCalculatorId[] | undefined;
protected dateFormat: string | undefined;
protected endDateRequired = false;
protected hintText: string | undefined;
protected startDateRequired = false;

protected formGroup = inject(FormBuilder).group({
lastDonation: new FormControl<SkyDateRangeCalculation>(
Expand Down Expand Up @@ -105,7 +103,7 @@ export class DateRangePickerComponent {
startDate: new Date('1/2/2012'),
endDate: new Date('1/1/2012'),
});
this.pickerFormControl.markAsDirty();
this.pickerFormControl.markAsTouched();
}

protected setUndefined(): void {
Expand All @@ -120,10 +118,6 @@ export class DateRangePickerComponent {
}
}

protected toggleEndDateRequired(): void {
this.endDateRequired = !this.endDateRequired;
}

protected toggleHintText(): void {
if (this.hintText) {
this.hintText = undefined;
Expand All @@ -141,8 +135,4 @@ export class DateRangePickerComponent {
}
this.pickerFormControl.updateValueAndValidity();
}

protected toggleStartDateRequired(): void {
this.startDateRequired = !this.startDateRequired;
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
<div
class="sky-date-range-picker"
[formGroup]="formGroup"
(focusout)="onBlur()"
>
<div class="sky-date-range-picker" [formGroup]="formGroup">
<div
class="sky-date-range-picker-form-group"
[ngClass]="{
Expand All @@ -11,7 +7,7 @@
}"
>
<sky-input-box
[hasErrors]="hasErrors"
[hasErrors]="calculatorIdHasErrors"
[helpKey]="helpKey"
[helpPopoverContent]="helpPopoverContent"
[helpPopoverTitle]="helpPopoverTitle"
Expand All @@ -22,11 +18,7 @@
('skyux_date_range_picker_default_label' | skyLibResources)
"
>
<select
formControlName="calculatorId"
[required]="isRequired()"
(blur)="onBlur()"
>
<select formControlName="calculatorId" (blur)="onBlur()">
@for (calculator of calculators; track calculator.calculatorId) {
<option [value]="calculator.calculatorId">
{{
Expand All @@ -38,8 +30,9 @@
}
</select>
@if (
hostControl?.errors?.['skyDateRange']?.errors.endDateBeforeStartDate &&
labelText
hostControl?.errors?.['skyDateRange']?.errors?.[
'endDateBeforeStartDate'
] && labelText
) {
<sky-form-error
[errorName]="'endDateBeforeStartDate'"
Expand All @@ -61,8 +54,7 @@
}"
>
<sky-input-box
[errorsScreenReaderOnly]="true"
[hasErrors]="hasErrors"
[hasErrors]="startDateHasErrors"
[labelText]="
selectedCalculator.type
| skyDateRangePickerStartDateResourceKey
Expand All @@ -88,9 +80,7 @@
| skyLibResources)
"
[dateFormat]="dateFormat"
[required]="
showStartDatePicker && (startDateRequired || isRequired())
"
[required]="showStartDatePicker && isRequired()"
/>
</sky-datepicker>
</sky-input-box>
Expand All @@ -101,8 +91,7 @@
[ngClass]="{ 'sky-date-range-picker-last-input': showEndDatePicker }"
>
<sky-input-box
[errorsScreenReaderOnly]="true"
[hasErrors]="hasErrors"
[hasErrors]="endDateHasErrors"
[labelText]="
selectedCalculator.type
| skyDateRangePickerEndDateResourceKey
Expand All @@ -128,7 +117,7 @@
| skyLibResources)
"
[dateFormat]="dateFormat"
[required]="showEndDatePicker && (endDateRequired || isRequired())"
[required]="showEndDatePicker && isRequired()"
/>
</sky-datepicker>
</sky-input-box>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,48 @@ describe('Date range picker', function () {
).toHaveCssClass('ng-touched');
});

it('should mark the underlying control touched if the host control calls markAllAsTouched', () => {
fixture.detectChanges();

component.reactiveForm?.markAllAsTouched();

fixture.detectChanges();

expect(
fixture.nativeElement.querySelector('sky-date-range-picker'),
).toHaveCssClass('ng-touched');
});

it('should mark only start date input as touched when start date is interacted with', () => {
fixture.detectChanges();

const datepickerInputs = fixture.nativeElement.querySelectorAll(
'.sky-input-group input',
);

SkyAppTestUtility.fireDomEvent(datepickerInputs.item(0), 'blur');

fixture.detectChanges();

expect(datepickerInputs.item(0)).toHaveCssClass('ng-touched');
expect(datepickerInputs.item(1)).toHaveCssClass('ng-untouched');
});

it('should mark only start date input as touched when start date is interacted with', () => {
fixture.detectChanges();

const datepickerInputs = fixture.nativeElement.querySelectorAll(
'.sky-input-group input',
);

SkyAppTestUtility.fireDomEvent(datepickerInputs.item(1), 'blur');

fixture.detectChanges();

expect(datepickerInputs.item(1)).toHaveCssClass('ng-touched');
expect(datepickerInputs.item(0)).toHaveCssClass('ng-untouched');
});

it('should maintain selected value when calculators change', fakeAsync(function () {
fixture.detectChanges();

Expand Down Expand Up @@ -633,16 +675,42 @@ describe('Date range picker', function () {
expect(calculatorIdControl?.errors).toBeFalsy();
}));

it('should visually set start and end date datepickers to required and not the calculator select', () => {
fixture.componentInstance.required = true;
fixture.detectChanges();

const control = component.dateRange;
control?.setValue({
calculatorId: SkyDateRangeCalculatorId.SpecificRange,
});
fixture.detectChanges();

const datepickerInputLabels =
fixture.nativeElement.querySelectorAll('.sky-control-label');
const calculatorSelectLabel = datepickerInputLabels.item(0);
const startDateLabel = datepickerInputLabels.item(1);
const endDateLabel = datepickerInputLabels.item(2);

expect(calculatorSelectLabel).not.toHaveCssClass(
'sky-control-label-required',
);
expect(startDateLabel).toHaveCssClass('sky-control-label-required');
expect(endDateLabel).toHaveCssClass('sky-control-label-required');
});

it('should show validation errors when start date is required but not provided', fakeAsync(function () {
fixture.componentInstance.startDateRequired = true;
fixture.componentInstance.required = true;
detectChanges();

const control = component.dateRange;
const calculatorIdControl =
component.dateRangePicker['formGroup']?.get('calculatorId');
const startDateControl =
component.dateRangePicker['formGroup']?.get('startDate');

control?.setValue({
calculatorId: SkyDateRangeCalculatorId.SpecificRange,
});
detectChanges();

const datepickerInputs = fixture.nativeElement.querySelectorAll(
'.sky-input-group input',
);
Expand All @@ -654,31 +722,34 @@ describe('Date range picker', function () {
};

expect(control?.errors).toEqual(expectedError);
expect(calculatorIdControl?.errors).toEqual(expectedError);
expect(startDateControl?.errors).toEqual(expectedError);
}));

it('should show validation errors when end date is required but not provided', fakeAsync(function () {
fixture.componentInstance.endDateRequired = true;
fixture.componentInstance.required = true;
detectChanges();

const control = component.dateRange;
const calculatorIdControl =
component.dateRangePicker['formGroup']?.get('calculatorId');
const endDateControl =
component.dateRangePicker['formGroup']?.get('endDate');

control?.setValue({
calculatorId: SkyDateRangeCalculatorId.SpecificRange,
});
detectChanges();

const datepickerInputs = fixture.nativeElement.querySelectorAll(
'.sky-input-group input',
);

SkyAppTestUtility.fireDomEvent(datepickerInputs.item(1), 'blur');
detectChanges();

const expectedError = {
required: true,
};

expect(control?.errors).toEqual(expectedError);
expect(calculatorIdControl?.errors).toEqual(expectedError);
expect(endDateControl?.errors).toEqual(expectedError);
}));

it('should log a deprecation warning when label input is used', fakeAsync(() => {
Expand All @@ -695,19 +766,25 @@ describe('Date range picker', function () {
}));

it('should render date range specific errors only when labelText is provided', fakeAsync(() => {
component.dateRange?.setValue({
const control = component.dateRange;

control?.setValue({
calculatorId: SkyDateRangeCalculatorId.SpecificRange,
startDate: new Date('1/2/2000'),
endDate: new Date('1/1/2000'),
});
component.reactiveForm.markAllAsTouched();
detectChanges();

control?.updateValueAndValidity();
control?.markAllAsTouched();
detectChanges();

expect(
fixture.nativeElement.querySelector('sky-form-error')?.textContent.trim(),
).toBe(undefined);

component.labelText = 'Date range picker';
control?.updateValueAndValidity();
detectChanges();

expect(
Expand All @@ -730,20 +807,15 @@ describe('Date range picker', function () {
function verifyFormFieldsRequired(expectation: boolean): void {
const inputBoxes =
fixture.nativeElement.querySelectorAll('sky-input-box');
const selectElement = fixture.nativeElement.querySelector('select');
const inputs = fixture.nativeElement.querySelectorAll('input');

expect(
inputBoxes.item(0).querySelector('.sky-control-label-required'),
).toEqual(expectation ? jasmine.any(HTMLLabelElement) : null);
expect(
inputBoxes.item(1).querySelector('.sky-control-label-required'),
).toEqual(expectation ? jasmine.any(HTMLLabelElement) : null);
expect(
inputBoxes.item(2).querySelector('.sky-control-label-required'),
).toEqual(expectation ? jasmine.any(HTMLLabelElement) : null);

expect(selectElement.hasAttribute('required')).toEqual(expectation);
expect(inputs.item(0).hasAttribute('required')).toEqual(expectation);
expect(inputs.item(1).hasAttribute('required')).toEqual(expectation);
}
Expand Down
Loading

0 comments on commit 052ea91

Please sign in to comment.