Skip to content

Commit 33a15ae

Browse files
authored
fix(datepicker): changed after checked error when moving preview between months (#19174)
Fixes a "changed after checked" error being thrown if the user has an active preview and they move to a different month using the keyboard. This is something that we had a fix for, but after #19088 it has to be moved one component up, because the binding that changes is in a different view.
1 parent e2c0c97 commit 33a15ae

File tree

3 files changed

+9
-16
lines changed

3 files changed

+9
-16
lines changed

src/material/datepicker/calendar-body.ts

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ import {
1818
OnChanges,
1919
SimpleChanges,
2020
OnDestroy,
21-
ChangeDetectorRef,
2221
} from '@angular/core';
2322
import {take} from 'rxjs/operators';
2423

@@ -132,11 +131,7 @@ export class MatCalendarBody implements OnChanges, OnDestroy {
132131
/** Width of an individual cell. */
133132
_cellWidth: string;
134133

135-
constructor(
136-
private _elementRef: ElementRef<HTMLElement>,
137-
private _changeDetectorRef: ChangeDetectorRef,
138-
private _ngZone: NgZone) {
139-
134+
constructor(private _elementRef: ElementRef<HTMLElement>, private _ngZone: NgZone) {
140135
_ngZone.runOutsideAngular(() => {
141136
const element = _elementRef.nativeElement;
142137
element.addEventListener('mouseenter', this._enterHandler, true);
@@ -321,15 +316,7 @@ export class MatCalendarBody implements OnChanges, OnDestroy {
321316
// we have a gap between the cells and the rows and we don't want to remove the
322317
// range just for it to show up again when the user moves a few pixels to the side.
323318
if (event.target && isTableCell(event.target as HTMLElement)) {
324-
this._ngZone.run(() => {
325-
this.previewChange.emit({value: null, event});
326-
327-
// Note that here we need to use `detectChanges`, rather than `markForCheck`, because
328-
// the way `_focusActiveCell` is set up at the moment makes it fire at the wrong time
329-
// when navigating one month back using the keyboard which will cause this handler
330-
// to throw a "changed after checked" error when updating the preview state.
331-
this._changeDetectorRef.detectChanges();
332-
});
319+
this._ngZone.run(() => this.previewChange.emit({value: null, event}));
333320
}
334321
}
335322
}

src/material/datepicker/month-view.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,12 @@ export class MatMonthView<D> implements AfterContentInit, OnDestroy {
332332
this._rangeStrategy.createPreview(value, this.selected as DateRange<D>, event);
333333
this._previewStart = this._getCellCompareValue(previewRange.start);
334334
this._previewEnd = this._getCellCompareValue(previewRange.end);
335+
336+
// Note that here we need to use `detectChanges`, rather than `markForCheck`, because
337+
// the way `_focusActiveCell` is set up at the moment makes it fire at the wrong time
338+
// when navigating one month back using the keyboard which will cause this handler
339+
// to throw a "changed after checked" error when updating the preview state.
340+
this._changeDetectorRef.detectChanges();
335341
}
336342
}
337343

tools/public_api_guard/material/datepicker.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ export declare class MatCalendarBody implements OnChanges, OnDestroy {
115115
readonly selectedValueChange: EventEmitter<MatCalendarUserEvent<number>>;
116116
startValue: number;
117117
todayValue: number;
118-
constructor(_elementRef: ElementRef<HTMLElement>, _changeDetectorRef: ChangeDetectorRef, _ngZone: NgZone);
118+
constructor(_elementRef: ElementRef<HTMLElement>, _ngZone: NgZone);
119119
_cellClicked(cell: MatCalendarCell, event: MouseEvent): void;
120120
_focusActiveCell(movePreview?: boolean): void;
121121
_isActiveCell(rowIndex: number, colIndex: number): boolean;

0 commit comments

Comments
 (0)