Skip to content

Commit

Permalink
fix(datepicker): calendar input changes not being propagated on child…
Browse files Browse the repository at this point in the history
… 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.
  • Loading branch information
crisbeto authored and jelbourn committed Jul 12, 2018
1 parent 32da038 commit b1d4fe1
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 3 deletions.
59 changes: 58 additions & 1 deletion src/lib/datepicker/calendar.spec.ts
Expand Up @@ -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';
Expand All @@ -32,6 +32,7 @@ describe('MatCalendar', () => {
StandardCalendar,
CalendarWithMinMax,
CalendarWithDateFilter,
CalendarWithSelectableMinDate,
],
providers: [
MatDatepickerIntl,
Expand Down Expand Up @@ -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', () => {
Expand Down Expand Up @@ -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;
}
}
7 changes: 5 additions & 2 deletions src/lib/datepicker/calendar.ts
Expand Up @@ -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');
Expand All @@ -288,7 +288,7 @@ export class MatCalendar<D> implements AfterContentInit, AfterViewChecked, OnDes
}

this._intlChanges = _intl.changes.subscribe(() => {
changeDetectorRef.markForCheck();
_changeDetectorRef.markForCheck();
this.stateChanges.next();
});
}
Expand Down Expand Up @@ -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();
}
}
Expand Down

0 comments on commit b1d4fe1

Please sign in to comment.