diff --git a/src/lib/datepicker/calendar.spec.ts b/src/lib/datepicker/calendar.spec.ts
index a5f389c473f..644271d203c 100644
--- a/src/lib/datepicker/calendar.spec.ts
+++ b/src/lib/datepicker/calendar.spec.ts
@@ -10,7 +10,7 @@ import {
} from '@angular/cdk/testing';
import {Component, NgZone} from '@angular/core';
import {ComponentFixture, TestBed, async, inject} from '@angular/core/testing';
-import {DEC, FEB, JAN, MatNativeDateModule, NOV} from '@angular/material/core';
+import {DEC, FEB, JAN, MatNativeDateModule, NOV, JUL} from '@angular/material/core';
import {By} from '@angular/platform-browser';
import {Direction, Directionality} from '@angular/cdk/bidi';
import {MatCalendar} from './calendar';
@@ -32,6 +32,7 @@ describe('MatCalendar', () => {
StandardCalendar,
CalendarWithMinMax,
CalendarWithDateFilter,
+ CalendarWithSelectableMinDate,
],
providers: [
MatDatepickerIntl,
@@ -399,6 +400,37 @@ describe('MatCalendar', () => {
expect(calendarInstance.multiYearView._init).toHaveBeenCalled();
});
+
+ it('should update the minDate in the child view if it changed after an interaction', () => {
+ fixture.destroy();
+
+ const dynamicFixture = TestBed.createComponent(CalendarWithSelectableMinDate);
+ dynamicFixture.detectChanges();
+
+ const calendarDebugElement = dynamicFixture.debugElement.query(By.directive(MatCalendar));
+ const disabledClass = 'mat-calendar-body-disabled';
+ calendarElement = calendarDebugElement.nativeElement;
+ calendarInstance = calendarDebugElement.componentInstance;
+
+ let cells = Array.from(calendarElement.querySelectorAll('.mat-calendar-body-cell'));
+
+ expect(cells.slice(0, 9).every(c => c.classList.contains(disabledClass)))
+ .toBe(true, 'Expected dates up to the 10th to be disabled.');
+
+ expect(cells.slice(9).every(c => c.classList.contains(disabledClass)))
+ .toBe(false, 'Expected dates after the 10th to be enabled.');
+
+ (cells[14] as HTMLElement).click();
+ dynamicFixture.detectChanges();
+ cells = Array.from(calendarElement.querySelectorAll('.mat-calendar-body-cell'));
+
+ expect(cells.slice(0, 14).every(c => c.classList.contains(disabledClass)))
+ .toBe(true, 'Expected dates up to the 14th to be disabled.');
+
+ expect(cells.slice(14).every(c => c.classList.contains(disabledClass)))
+ .toBe(false, 'Expected dates after the 14th to be enabled.');
+ });
+
});
describe('calendar with date filter', () => {
@@ -521,3 +553,28 @@ class CalendarWithDateFilter {
return !(date.getDate() % 2) && date.getMonth() !== NOV;
}
}
+
+
+@Component({
+ template: `
+
+
+ `
+})
+class CalendarWithSelectableMinDate {
+ startAt = new Date(2018, JUL, 0);
+ selected: Date;
+ minDate: Date;
+
+ constructor() {
+ this.select(new Date(2018, JUL, 10));
+ }
+
+ select(value: Date) {
+ this.minDate = this.selected = value;
+ }
+}
diff --git a/src/lib/datepicker/calendar.ts b/src/lib/datepicker/calendar.ts
index a1215d3ec4d..4c3411e3c50 100644
--- a/src/lib/datepicker/calendar.ts
+++ b/src/lib/datepicker/calendar.ts
@@ -277,7 +277,7 @@ export class MatCalendar implements AfterContentInit, AfterViewChecked, OnDes
constructor(_intl: MatDatepickerIntl,
@Optional() private _dateAdapter: DateAdapter,
@Optional() @Inject(MAT_DATE_FORMATS) private _dateFormats: MatDateFormats,
- changeDetectorRef: ChangeDetectorRef) {
+ private _changeDetectorRef: ChangeDetectorRef) {
if (!this._dateAdapter) {
throw createMissingDateImplError('DateAdapter');
@@ -288,7 +288,7 @@ export class MatCalendar implements AfterContentInit, AfterViewChecked, OnDes
}
this._intlChanges = _intl.changes.subscribe(() => {
- changeDetectorRef.markForCheck();
+ _changeDetectorRef.markForCheck();
this.stateChanges.next();
});
}
@@ -320,6 +320,9 @@ export class MatCalendar implements AfterContentInit, AfterViewChecked, OnDes
const view = this._getCurrentViewComponent();
if (view) {
+ // 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();
view._init();
}
}