Skip to content

Commit 96f968e

Browse files
authored
fix(datepicker): move focus into start input when pressing backspace on end input (#19239)
Makes it so that pressing backspace on an empty end input moves focus into the start input. This makes the two separate inputs feel a bit more like a single input.
1 parent 5e8a974 commit 96f968e

File tree

3 files changed

+43
-1
lines changed

3 files changed

+43
-1
lines changed

src/material/datepicker/date-range-input-parts.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import {
3838
ErrorStateMatcher,
3939
} from '@angular/material/core';
4040
import {BooleanInput} from '@angular/cdk/coercion';
41+
import {BACKSPACE} from '@angular/cdk/keycodes';
4142
import {MatDatepickerInputBase, DateFilterFn} from './datepicker-input-base';
4243
import {DateRange, MatDateSelectionModel} from './date-selection-model';
4344

@@ -47,6 +48,8 @@ export interface MatDateRangeInputParent<D> {
4748
min: D | null;
4849
max: D | null;
4950
dateFilter: DateFilterFn<D>;
51+
_startInput: MatDateRangeInputPartBase<D>;
52+
_endInput: MatDateRangeInputPartBase<D>;
5053
_groupDisabled: boolean;
5154
_ariaDescribedBy: string | null;
5255
_ariaLabelledBy: string | null;
@@ -319,5 +322,14 @@ export class MatEndDate<D> extends _MatDateRangeInputBase<D> implements CanUpdat
319322
}
320323
}
321324

325+
_onKeydown(event: KeyboardEvent) {
326+
// If the user is pressing backspace on an empty end input, focus focus back to the start.
327+
if (event.keyCode === BACKSPACE && !this._elementRef.nativeElement.value) {
328+
this._rangeInput._startInput.focus();
329+
}
330+
331+
super._onKeydown(event);
332+
}
333+
322334
static ngAcceptInputType_disabled: BooleanInput;
323335
}

src/material/datepicker/date-range-input.spec.ts

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@ import {MatNativeDateModule} from '@angular/material/core';
77
import {MatDatepickerModule} from './datepicker-module';
88
import {MatFormFieldModule} from '@angular/material/form-field';
99
import {MatInputModule} from '@angular/material/input';
10-
import {dispatchFakeEvent} from '@angular/cdk/testing/private';
10+
import {dispatchFakeEvent, dispatchKeyboardEvent} from '@angular/cdk/testing/private';
1111
import {FocusMonitor} from '@angular/cdk/a11y';
12+
import {BACKSPACE} from '@angular/cdk/keycodes';
1213
import {MatDateRangeInput} from './date-range-input';
1314
import {MatDateRangePicker} from './date-range-picker';
1415

@@ -473,6 +474,34 @@ describe('MatDateRangeInput', () => {
473474
expect(fixture.componentInstance.end).toBe(end);
474475
}));
475476

477+
it('should move focus to the start input when pressing backspace on an empty end input', () => {
478+
const fixture = createComponent(StandardRangePicker);
479+
fixture.detectChanges();
480+
const {start, end} = fixture.componentInstance;
481+
482+
spyOn(start.nativeElement, 'focus').and.callThrough();
483+
484+
end.nativeElement.value = '';
485+
dispatchKeyboardEvent(end.nativeElement, 'keydown', BACKSPACE);
486+
fixture.detectChanges();
487+
488+
expect(start.nativeElement.focus).toHaveBeenCalled();
489+
});
490+
491+
it('should move not move focus when pressing backspace if the end input has a value', () => {
492+
const fixture = createComponent(StandardRangePicker);
493+
fixture.detectChanges();
494+
const {start, end} = fixture.componentInstance;
495+
496+
spyOn(start.nativeElement, 'focus').and.callThrough();
497+
498+
end.nativeElement.value = '10/10/2020';
499+
dispatchKeyboardEvent(end.nativeElement, 'keydown', BACKSPACE);
500+
fixture.detectChanges();
501+
502+
expect(start.nativeElement.focus).not.toHaveBeenCalled();
503+
});
504+
476505
});
477506

478507
@Component({

tools/public_api_guard/material/datepicker.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,7 @@ export declare class MatEndDate<D> extends _MatDateRangeInputBase<D> implements
367367
constructor(rangeInput: MatDateRangeInputParent<D>, elementRef: ElementRef<HTMLInputElement>, defaultErrorStateMatcher: ErrorStateMatcher, injector: Injector, parentForm: NgForm, parentFormGroup: FormGroupDirective, dateAdapter: DateAdapter<D>, dateFormats: MatDateFormats);
368368
protected _assignValueToModel(value: D | null): void;
369369
protected _getValueFromModel(modelValue: DateRange<D>): D | null;
370+
_onKeydown(event: KeyboardEvent): void;
370371
static ngAcceptInputType_disabled: BooleanInput;
371372
static ɵdir: i0.ɵɵDirectiveDefWithMeta<MatEndDate<any>, "input[matEndDate]", never, {}, {}, never>;
372373
static ɵfac: i0.ɵɵFactoryDef<MatEndDate<any>, [null, null, null, null, { optional: true; }, { optional: true; }, { optional: true; }, { optional: true; }]>;

0 commit comments

Comments
 (0)