Skip to content

Commit 60abc41

Browse files
committed
Revert "fix(material/datepicker): update active date on focusing a calendar cell (#24279)" (#24380)
This reverts commit 052b97d. (cherry picked from commit e04e4a7)
1 parent f5199ee commit 60abc41

12 files changed

+33
-262
lines changed

src/material/datepicker/calendar-body.html

+1-2
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,7 @@
6363
[attr.aria-disabled]="!item.enabled || null"
6464
[attr.aria-pressed]="_isSelected(item.compareValue)"
6565
[attr.aria-current]="todayValue === item.compareValue ? 'date' : null"
66-
(click)="_cellClicked(item, $event)"
67-
(focus)="_emitActiveDateChange(item, $event)">
66+
(click)="_cellClicked(item, $event)">
6867
<div class="mat-calendar-body-cell-content mat-focus-indicator"
6968
[class.mat-calendar-body-selected]="_isSelected(item.compareValue)"
7069
[class.mat-calendar-body-comparison-identical]="_isComparisonIdentical(item.compareValue)"

src/material/datepicker/calendar-body.ts

+1-27
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ import {
1818
OnChanges,
1919
SimpleChanges,
2020
OnDestroy,
21-
AfterViewChecked,
2221
} from '@angular/core';
2322
import {take} from 'rxjs/operators';
2423

@@ -68,18 +67,13 @@ export interface MatCalendarUserEvent<D> {
6867
encapsulation: ViewEncapsulation.None,
6968
changeDetection: ChangeDetectionStrategy.OnPush,
7069
})
71-
export class MatCalendarBody implements OnChanges, OnDestroy, AfterViewChecked {
70+
export class MatCalendarBody implements OnChanges, OnDestroy {
7271
/**
7372
* Used to skip the next focus event when rendering the preview range.
7473
* We need a flag like this, because some browsers fire focus events asynchronously.
7574
*/
7675
private _skipNextFocus: boolean;
7776

78-
/**
79-
* Used to focus the active cell after change detection has run.
80-
*/
81-
private _focusActiveCellAfterViewChecked = false;
82-
8377
/** The label for the table. (e.g. "Jan 2017"). */
8478
@Input() label: string;
8579

@@ -104,13 +98,6 @@ export class MatCalendarBody implements OnChanges, OnDestroy, AfterViewChecked {
10498
/** The cell number of the active cell in the table. */
10599
@Input() activeCell: number = 0;
106100

107-
ngAfterViewChecked() {
108-
if (this._focusActiveCellAfterViewChecked) {
109-
this._focusActiveCell();
110-
this._focusActiveCellAfterViewChecked = false;
111-
}
112-
}
113-
114101
/** Whether a range is being selected. */
115102
@Input() isRange: boolean = false;
116103

@@ -140,8 +127,6 @@ export class MatCalendarBody implements OnChanges, OnDestroy, AfterViewChecked {
140127
MatCalendarUserEvent<MatCalendarCell | null>
141128
>();
142129

143-
@Output() readonly activeDateChange = new EventEmitter<MatCalendarUserEvent<number>>();
144-
145130
/** The number of blank cells to put at the beginning for the first row. */
146131
_firstRowOffset: number;
147132

@@ -168,12 +153,6 @@ export class MatCalendarBody implements OnChanges, OnDestroy, AfterViewChecked {
168153
}
169154
}
170155

171-
_emitActiveDateChange(cell: MatCalendarCell, event: FocusEvent): void {
172-
if (cell.enabled) {
173-
this.activeDateChange.emit({value: cell.value, event});
174-
}
175-
}
176-
177156
/** Returns whether a cell should be marked as selected. */
178157
_isSelected(value: number) {
179158
return this.startValue === value || this.endValue === value;
@@ -235,11 +214,6 @@ export class MatCalendarBody implements OnChanges, OnDestroy, AfterViewChecked {
235214
});
236215
}
237216

238-
/** Focuses the active cell after change detection has run and the microtask queue is empty. */
239-
_scheduleFocusActiveCellAfterViewChecked() {
240-
this._focusActiveCellAfterViewChecked = true;
241-
}
242-
243217
/** Gets whether a value is the start of the main range. */
244218
_isRangeStart(value: number) {
245219
return isStart(value, this.startValue, this.endValue);

src/material/datepicker/month-view.html

-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
[labelMinRequiredCells]="3"
2222
[activeCell]="_dateAdapter.getDate(activeDate) - 1"
2323
(selectedValueChange)="_dateSelected($event)"
24-
(activeDateChange)="_updateActiveDate($event)"
2524
(previewChange)="_previewChanged($event)"
2625
(keyup)="_handleCalendarBodyKeyup($event)"
2726
(keydown)="_handleCalendarBodyKeydown($event)">

src/material/datepicker/month-view.spec.ts

-24
Original file line numberDiff line numberDiff line change
@@ -520,30 +520,6 @@ describe('MatMonthView', () => {
520520
);
521521
},
522522
);
523-
524-
it('should go to month that is focused', () => {
525-
const jan11Cell = fixture.debugElement.nativeElement.querySelector(
526-
'[data-mat-row="1"][data-mat-col="3"] button',
527-
) as HTMLElement;
528-
529-
dispatchFakeEvent(jan11Cell, 'focus');
530-
fixture.detectChanges();
531-
532-
expect(calendarInstance.date).toEqual(new Date(2017, JAN, 11));
533-
});
534-
535-
it('should not call `.focus()` when the active date is focused', () => {
536-
const jan5Cell = fixture.debugElement.nativeElement.querySelector(
537-
'[data-mat-row="0"][data-mat-col="4"] button',
538-
) as HTMLElement;
539-
const focusSpy = (jan5Cell.focus = jasmine.createSpy('cellFocused'));
540-
541-
dispatchFakeEvent(jan5Cell, 'focus');
542-
fixture.detectChanges();
543-
544-
expect(calendarInstance.date).toEqual(new Date(2017, JAN, 5));
545-
expect(focusSpy).not.toHaveBeenCalled();
546-
});
547523
});
548524
});
549525
});

src/material/datepicker/month-view.ts

+4-40
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,9 @@ export class MatMonthView<D> implements AfterContentInit, OnChanges, OnDestroy {
230230
/** Handles when a new date is selected. */
231231
_dateSelected(event: MatCalendarUserEvent<number>) {
232232
const date = event.value;
233-
const selectedDate = this._getDateFromDayOfMonth(date);
233+
const selectedYear = this._dateAdapter.getYear(this.activeDate);
234+
const selectedMonth = this._dateAdapter.getMonth(this.activeDate);
235+
const selectedDate = this._dateAdapter.createDate(selectedYear, selectedMonth, date);
234236
let rangeStartDate: number | null;
235237
let rangeEndDate: number | null;
236238

@@ -250,26 +252,6 @@ export class MatMonthView<D> implements AfterContentInit, OnChanges, OnDestroy {
250252
this._changeDetectorRef.markForCheck();
251253
}
252254

253-
/**
254-
* Takes the index of a calendar body cell wrapped in in an event as argument. For the date that
255-
* corresponds to the given cell, set `activeDate` to that date and fire `activeDateChange` with
256-
* that date.
257-
*
258-
* This fucntion is used to match each component's model of the active date with the calendar
259-
* body cell that was focused. It updates its value of `activeDate` synchronously and updates the
260-
* parent's value asynchonously via the `activeDateChange` event. The child component receives an
261-
* updated value asynchronously via the `activeCell` Input.
262-
*/
263-
_updateActiveDate(event: MatCalendarUserEvent<number>) {
264-
const month = event.value;
265-
const oldActiveDate = this._activeDate;
266-
this.activeDate = this._getDateFromDayOfMonth(month);
267-
268-
if (this._dateAdapter.compareDate(oldActiveDate, this.activeDate)) {
269-
this.activeDateChange.emit(this._activeDate);
270-
}
271-
}
272-
273255
/** Handles keydown events on the calendar body when calendar is in month view. */
274256
_handleCalendarBodyKeydown(event: KeyboardEvent): void {
275257
// TODO(mmalerba): We currently allow keyboard navigation to disabled dates, but just prevent
@@ -345,10 +327,9 @@ export class MatMonthView<D> implements AfterContentInit, OnChanges, OnDestroy {
345327

346328
if (this._dateAdapter.compareDate(oldActiveDate, this.activeDate)) {
347329
this.activeDateChange.emit(this.activeDate);
348-
349-
this._focusActiveCellAfterViewChecked();
350330
}
351331

332+
this._focusActiveCell();
352333
// Prevent unexpected default actions such as form submission.
353334
event.preventDefault();
354335
}
@@ -395,11 +376,6 @@ export class MatMonthView<D> implements AfterContentInit, OnChanges, OnDestroy {
395376
this._matCalendarBody._focusActiveCell(movePreview);
396377
}
397378

398-
/** Focuses the active cell after change detection has run and the microtask queue is empty. */
399-
_focusActiveCellAfterViewChecked() {
400-
this._matCalendarBody._scheduleFocusActiveCellAfterViewChecked();
401-
}
402-
403379
/** Called when the user has activated a new cell and the preview needs to be updated. */
404380
_previewChanged({event, value: cell}: MatCalendarUserEvent<MatCalendarCell<D> | null>) {
405381
if (this._rangeStrategy) {
@@ -422,18 +398,6 @@ export class MatMonthView<D> implements AfterContentInit, OnChanges, OnDestroy {
422398
}
423399
}
424400

425-
/**
426-
* Takes a day of the month and returns a new date in the same month and year as the currently
427-
* active date. The returned date will have the same day of the month as the argument date.
428-
*/
429-
private _getDateFromDayOfMonth(dayOfMonth: number): D {
430-
return this._dateAdapter.createDate(
431-
this._dateAdapter.getYear(this.activeDate),
432-
this._dateAdapter.getMonth(this.activeDate),
433-
dayOfMonth,
434-
);
435-
}
436-
437401
/** Initializes the weekdays. */
438402
private _initWeekdays() {
439403
const firstDayOfWeek = this._dateAdapter.getFirstDayOfWeek();

src/material/datepicker/multi-year-view.html

-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
[cellAspectRatio]="4 / 7"
1212
[activeCell]="_getActiveCell()"
1313
(selectedValueChange)="_yearSelected($event)"
14-
(activeDateChange)="_updateActiveDate($event)"
1514
(keyup)="_handleCalendarBodyKeyup($event)"
1615
(keydown)="_handleCalendarBodyKeydown($event)">
1716
</tbody>

src/material/datepicker/multi-year-view.spec.ts

+1-29
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {dispatchFakeEvent, dispatchKeyboardEvent} from '../../cdk/testing/privat
1313
import {Component, ViewChild} from '@angular/core';
1414
import {waitForAsync, ComponentFixture, TestBed} from '@angular/core/testing';
1515
import {MatNativeDateModule} from '@angular/material/core';
16-
import {JAN, MAR} from '../testing';
16+
import {JAN} from '../testing';
1717
import {By} from '@angular/platform-browser';
1818
import {MatCalendarBody} from './calendar-body';
1919
import {MatMultiYearView, yearsPerPage, yearsPerRow} from './multi-year-view';
@@ -216,34 +216,6 @@ describe('MatMultiYearView', () => {
216216

217217
expect(calendarInstance.date).toEqual(new Date(2017 + yearsPerPage * 2, JAN, 1));
218218
});
219-
220-
it('should go to the year that is focused', () => {
221-
fixture.componentInstance.date = new Date(2017, MAR, 5);
222-
fixture.detectChanges();
223-
expect(calendarInstance.date).toEqual(new Date(2017, MAR, 5));
224-
225-
const year2022Cell = fixture.debugElement.nativeElement.querySelector(
226-
'[data-mat-row="1"][data-mat-col="2"] button',
227-
) as HTMLElement;
228-
229-
dispatchFakeEvent(year2022Cell, 'focus');
230-
fixture.detectChanges();
231-
232-
expect(calendarInstance.date).toEqual(new Date(2022, MAR, 5));
233-
});
234-
235-
it('should not call `.focus()` when the active date is focused', () => {
236-
const year2017Cell = fixture.debugElement.nativeElement.querySelector(
237-
'[data-mat-row="0"][data-mat-col="1"] button',
238-
) as HTMLElement;
239-
const focusSpy = (year2017Cell.focus = jasmine.createSpy('cellFocused'));
240-
241-
dispatchFakeEvent(year2017Cell, 'focus');
242-
fixture.detectChanges();
243-
244-
expect(calendarInstance.date).toEqual(new Date(2017, JAN, 1));
245-
expect(focusSpy).not.toHaveBeenCalled();
246-
});
247219
});
248220
});
249221
});

src/material/datepicker/multi-year-view.ts

+13-48
Original file line numberDiff line numberDiff line change
@@ -204,31 +204,18 @@ export class MatMultiYearView<D> implements AfterContentInit, OnDestroy {
204204
/** Handles when a new year is selected. */
205205
_yearSelected(event: MatCalendarUserEvent<number>) {
206206
const year = event.value;
207-
const selectedYear = this._dateAdapter.createDate(year, 0, 1);
208-
const selectedDate = this._getDateFromYear(year);
209-
210-
this.yearSelected.emit(selectedYear);
211-
this.selectedChange.emit(selectedDate);
212-
}
213-
214-
/**
215-
* Takes the index of a calendar body cell wrapped in in an event as argument. For the date that
216-
* corresponds to the given cell, set `activeDate` to that date and fire `activeDateChange` with
217-
* that date.
218-
*
219-
* This fucntion is used to match each component's model of the active date with the calendar
220-
* body cell that was focused. It updates its value of `activeDate` synchronously and updates the
221-
* parent's value asynchonously via the `activeDateChange` event. The child component receives an
222-
* updated value asynchronously via the `activeCell` Input.
223-
*/
224-
_updateActiveDate(event: MatCalendarUserEvent<number>) {
225-
const year = event.value;
226-
const oldActiveDate = this._activeDate;
227-
228-
this.activeDate = this._getDateFromYear(year);
229-
if (this._dateAdapter.compareDate(oldActiveDate, this.activeDate)) {
230-
this.activeDateChange.emit(this.activeDate);
231-
}
207+
this.yearSelected.emit(this._dateAdapter.createDate(year, 0, 1));
208+
let month = this._dateAdapter.getMonth(this.activeDate);
209+
let daysInMonth = this._dateAdapter.getNumDaysInMonth(
210+
this._dateAdapter.createDate(year, month, 1),
211+
);
212+
this.selectedChange.emit(
213+
this._dateAdapter.createDate(
214+
year,
215+
month,
216+
Math.min(this._dateAdapter.getDate(this.activeDate), daysInMonth),
217+
),
218+
);
232219
}
233220

234221
/** Handles keydown events on the calendar body when calendar is in multi-year view. */
@@ -291,7 +278,7 @@ export class MatMultiYearView<D> implements AfterContentInit, OnDestroy {
291278
this.activeDateChange.emit(this.activeDate);
292279
}
293280

294-
this._focusActiveCellAfterViewChecked();
281+
this._focusActiveCell();
295282
// Prevent unexpected default actions such as form submission.
296283
event.preventDefault();
297284
}
@@ -316,28 +303,6 @@ export class MatMultiYearView<D> implements AfterContentInit, OnDestroy {
316303
this._matCalendarBody._focusActiveCell();
317304
}
318305

319-
/** Focuses the active cell after change detection has run and the microtask queue is empty. */
320-
_focusActiveCellAfterViewChecked() {
321-
this._matCalendarBody._scheduleFocusActiveCellAfterViewChecked();
322-
}
323-
324-
/**
325-
* Takes a year and returns a new date on the same day and month as the currently active date
326-
* The returned date will have the same year as the argument date.
327-
*/
328-
private _getDateFromYear(year: number) {
329-
const activeMonth = this._dateAdapter.getMonth(this.activeDate);
330-
const daysInMonth = this._dateAdapter.getNumDaysInMonth(
331-
this._dateAdapter.createDate(year, activeMonth, 1),
332-
);
333-
const normalizedDate = this._dateAdapter.createDate(
334-
year,
335-
activeMonth,
336-
Math.min(this._dateAdapter.getDate(this.activeDate), daysInMonth),
337-
);
338-
return normalizedDate;
339-
}
340-
341306
/** Creates an MatCalendarCell for the given year. */
342307
private _createCellForYear(year: number) {
343308
const date = this._dateAdapter.createDate(year, 0, 1);

src/material/datepicker/year-view.html

-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
[cellAspectRatio]="4 / 7"
1414
[activeCell]="_dateAdapter.getMonth(activeDate)"
1515
(selectedValueChange)="_monthSelected($event)"
16-
(activeDateChange)="_updateActiveDate($event)"
1716
(keyup)="_handleCalendarBodyKeyup($event)"
1817
(keydown)="_handleCalendarBodyKeydown($event)">
1918
</tbody>

src/material/datepicker/year-view.spec.ts

-24
Original file line numberDiff line numberDiff line change
@@ -292,30 +292,6 @@ describe('MatYearView', () => {
292292

293293
expect(calendarInstance.date).toEqual(new Date(2018, FEB, 28));
294294
});
295-
296-
it('should go to date that is focused', () => {
297-
const juneCell = fixture.debugElement.nativeElement.querySelector(
298-
'[data-mat-row="1"][data-mat-col="1"] button',
299-
) as HTMLElement;
300-
301-
dispatchFakeEvent(juneCell, 'focus');
302-
fixture.detectChanges();
303-
304-
expect(calendarInstance.date).toEqual(new Date(2017, JUN, 5));
305-
});
306-
307-
it('should not call `.focus()` when the active date is focused', () => {
308-
const janCell = fixture.debugElement.nativeElement.querySelector(
309-
'[data-mat-row="0"][data-mat-col="0"] button',
310-
) as HTMLElement;
311-
const focusSpy = (janCell.focus = jasmine.createSpy('cellFocused'));
312-
313-
dispatchFakeEvent(janCell, 'focus');
314-
fixture.detectChanges();
315-
316-
expect(calendarInstance.date).toEqual(new Date(2017, JAN, 5));
317-
expect(focusSpy).not.toHaveBeenCalled();
318-
});
319295
});
320296
});
321297
});

0 commit comments

Comments
 (0)