fix(datepicker): calendar input changes not being propagated on child views (#12004)

Fixes the new values for the calendar's `minDate`, `maxDate` and `dateFilter` not being propagated to the current calendar view until the next change detection cycle.

Fixes #11737.
This commit is contained in:
Kristiyan Kostadinov
2018-07-12 16:53:09 +02:00
committed by Jeremy Elbourn
parent 32da0388ce
commit b1d4fe15b7
2 changed files with 63 additions and 3 deletions
+58 -1
View File
@@ -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: `
<mat-calendar
[startAt]="startAt"
(selectedChange)="select($event)"
[selected]="selected"
[minDate]="selected">
</mat-calendar>
`
})
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;
}
}
+5 -2
View File
@@ -277,7 +277,7 @@ export class MatCalendar<D> implements AfterContentInit, AfterViewChecked, OnDes
constructor(_intl: MatDatepickerIntl,
@Optional() private _dateAdapter: DateAdapter<D>,
@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<D> implements AfterContentInit, AfterViewChecked, OnDes
}
this._intlChanges = _intl.changes.subscribe(() => {
changeDetectorRef.markForCheck();
_changeDetectorRef.markForCheck();
this.stateChanges.next();
});
}
@@ -320,6 +320,9 @@ export class MatCalendar<D> 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();
}
}