From a7aaf1e5e561578b04fcc4ee81c4638fcba2acc2 Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Thu, 20 Jun 2024 11:15:27 +0200 Subject: [PATCH] fix(material/datepicker): avoid losing focus when re-rendering the current view When some calendar inputs change, we need to re-render the entire view (e.g. `minDate` or `dateFilter`). This can cause the active cell to lose focus since it's being re-rendered. These changes schedule the active cell to be re-focused in the cases where the view would be re-rendered. Fixes #29265. --- src/material/datepicker/calendar.ts | 8 ++++++-- src/material/datepicker/datepicker.spec.ts | 2 ++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/material/datepicker/calendar.ts b/src/material/datepicker/calendar.ts index ad9501c3ae0a..44aa938c3147 100644 --- a/src/material/datepicker/calendar.ts +++ b/src/material/datepicker/calendar.ts @@ -454,12 +454,16 @@ export class MatCalendar implements AfterContentInit, AfterViewChecked, OnDes ? changes['maxDate'] : undefined; - const change = minDateChange || maxDateChange || changes['dateFilter']; + const changeRequiringRerender = minDateChange || maxDateChange || changes['dateFilter']; - if (change && !change.firstChange) { + if (changeRequiringRerender && !changeRequiringRerender.firstChange) { const view = this._getCurrentViewComponent(); if (view) { + // Schedule focus to be moved to the active date since re-rendering + // can blur the active cell. See #29265. + this._moveFocusOnNextTick = true; + // We need to `detectChanges` manually here, because the `minDate`, `maxDate` etc. are // passed down to the view via data bindings which won't be up-to-date when we call `_init`. this._changeDetectorRef.detectChanges(); diff --git a/src/material/datepicker/datepicker.spec.ts b/src/material/datepicker/datepicker.spec.ts index b63f518b46c3..fef4abbe8081 100644 --- a/src/material/datepicker/datepicker.spec.ts +++ b/src/material/datepicker/datepicker.spec.ts @@ -1726,6 +1726,7 @@ describe('MatDatepicker', () => { testComponent.minDate = new Date(2020, JAN, 1); fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); + flush(); expect(getDisabledCells()).not.toBe(disabledCellCount); disabledCellCount = getDisabledCells(); @@ -1733,6 +1734,7 @@ describe('MatDatepicker', () => { testComponent.maxDate = new Date(2020, JAN, 10); fixture.changeDetectorRef.markForCheck(); fixture.detectChanges(); + flush(); expect(getDisabledCells()).not.toBe(disabledCellCount); }));