diff --git a/src/lib/datepicker/datepicker.spec.ts b/src/lib/datepicker/datepicker.spec.ts
index 81576b717270..85ce44aae18d 100644
--- a/src/lib/datepicker/datepicker.spec.ts
+++ b/src/lib/datepicker/datepicker.spec.ts
@@ -28,7 +28,6 @@ import {MatDatepickerInput} from './datepicker-input';
import {MatDatepickerToggle} from './datepicker-toggle';
import {MatDatepickerIntl, MatDatepickerModule} from './index';
-
describe('MatDatepicker', () => {
const SUPPORTS_INTL = typeof Intl != 'undefined';
@@ -113,6 +112,18 @@ describe('MatDatepicker', () => {
.not.toBeNull();
});
+ it('should open datepicker if opened input is set to true', () => {
+ testComponent.opened = true;
+ fixture.detectChanges();
+
+ expect(document.querySelector('.mat-datepicker-content')).not.toBeNull();
+
+ testComponent.opened = false;
+ fixture.detectChanges();
+
+ expect(document.querySelector('.mat-datepicker-content')).toBeNull();
+ });
+
it('open in disabled mode should not open the calendar', () => {
testComponent.disabled = true;
fixture.detectChanges();
@@ -151,9 +162,7 @@ describe('MatDatepicker', () => {
testComponent.datepicker.close();
fixture.detectChanges();
- fixture.whenStable().then(() => {
- expect(parseInt(getComputedStyle(popup).height as string)).toBe(0);
- });
+ expect(parseInt(getComputedStyle(popup).height as string)).toBe(0);
});
it('should close the popup when pressing ESCAPE', () => {
@@ -177,7 +186,7 @@ describe('MatDatepicker', () => {
.toBe(true, 'Expected default ESCAPE action to be prevented.');
});
- it('close should close dialog', () => {
+ it('close should close dialog', async(() => {
testComponent.touch = true;
fixture.detectChanges();
@@ -192,9 +201,9 @@ describe('MatDatepicker', () => {
fixture.whenStable().then(() => {
expect(document.querySelector('mat-dialog-container')).toBeNull();
});
- });
+ }));
- it('setting selected should update input and close calendar', () => {
+ it('setting selected should update input and close calendar', async(() => {
testComponent.touch = true;
fixture.detectChanges();
@@ -212,12 +221,13 @@ describe('MatDatepicker', () => {
expect(document.querySelector('mat-dialog-container')).toBeNull();
expect(testComponent.datepickerInput.value).toEqual(new Date(2020, JAN, 2));
});
- });
+ }));
it('clicking the currently selected date should close the calendar ' +
'without firing selectedChanged', () => {
const selectedChangedSpy =
spyOn(testComponent.datepicker.selectedChanged, 'emit').and.callThrough();
+
for (let changeCount = 1; changeCount < 3; changeCount++) {
const currentDay = changeCount;
testComponent.datepicker.open();
@@ -231,11 +241,9 @@ describe('MatDatepicker', () => {
fixture.detectChanges();
}
- fixture.whenStable().then(() => {
- expect(selectedChangedSpy.calls.count()).toEqual(1);
- expect(document.querySelector('mat-dialog-container')).toBeNull();
- expect(testComponent.datepickerInput.value).toEqual(new Date(2020, JAN, 2));
- });
+ expect(selectedChangedSpy.calls.count()).toEqual(1);
+ expect(document.querySelector('mat-dialog-container')).toBeNull();
+ expect(testComponent.datepickerInput.value).toEqual(new Date(2020, JAN, 2));
});
it('startAt should fallback to input value', () => {
@@ -479,7 +487,7 @@ describe('MatDatepicker', () => {
expect(inputEl.classList).toContain('ng-touched');
});
- it('should mark input touched on calendar selection', () => {
+ it('should mark input touched on calendar selection', async(() => {
let inputEl = fixture.debugElement.query(By.css('input')).nativeElement;
expect(inputEl.classList).toContain('ng-untouched');
@@ -492,7 +500,7 @@ describe('MatDatepicker', () => {
expect(inputEl.classList).toContain('ng-touched');
});
- });
+ }));
});
describe('datepicker with formControl', () => {
@@ -702,7 +710,7 @@ describe('MatDatepicker', () => {
expect(testComponent.datepicker._maxDate).toEqual(new Date(2020, JAN, 1));
});
- it('should mark invalid when value is before min', () => {
+ it('should mark invalid when value is before min', async(() => {
testComponent.date = new Date(2009, DEC, 31);
fixture.detectChanges();
@@ -712,9 +720,9 @@ describe('MatDatepicker', () => {
expect(fixture.debugElement.query(By.css('input')).nativeElement.classList)
.toContain('ng-invalid');
});
- });
+ }));
- it('should mark invalid when value is after max', () => {
+ it('should mark invalid when value is after max', async(() => {
testComponent.date = new Date(2020, JAN, 2);
fixture.detectChanges();
@@ -724,9 +732,9 @@ describe('MatDatepicker', () => {
expect(fixture.debugElement.query(By.css('input')).nativeElement.classList)
.toContain('ng-invalid');
});
- });
+ }));
- it('should not mark invalid when value equals min', () => {
+ it('should not mark invalid when value equals min', async(() => {
testComponent.date = testComponent.datepicker._minDate;
fixture.detectChanges();
@@ -736,9 +744,9 @@ describe('MatDatepicker', () => {
expect(fixture.debugElement.query(By.css('input')).nativeElement.classList)
.not.toContain('ng-invalid');
});
- });
+ }));
- it('should not mark invalid when value equals max', () => {
+ it('should not mark invalid when value equals max', async(() => {
testComponent.date = testComponent.datepicker._maxDate;
fixture.detectChanges();
@@ -748,9 +756,9 @@ describe('MatDatepicker', () => {
expect(fixture.debugElement.query(By.css('input')).nativeElement.classList)
.not.toContain('ng-invalid');
});
- });
+ }));
- it('should not mark invalid when value is between min and max', () => {
+ it('should not mark invalid when value is between min and max', async(() => {
testComponent.date = new Date(2010, JAN, 2);
fixture.detectChanges();
@@ -760,7 +768,7 @@ describe('MatDatepicker', () => {
expect(fixture.debugElement.query(By.css('input')).nativeElement.classList)
.not.toContain('ng-invalid');
});
- });
+ }));
});
describe('datepicker with filter and validation', () => {
@@ -1078,17 +1086,27 @@ describe('MatDatepicker', () => {
input = fixture.nativeElement.querySelector('input') as HTMLInputElement;
}));
- it('should have the correct input value even when inverted date format', () => {
- let selected = new Date(2017, SEP, 1);
+ it('should have the correct input value even when inverted date format', async(() => {
+ if (typeof Intl === 'undefined') {
+ // Skip this test if the internationalization API is not supported in the current
+ // browser. Browsers like Safari 9 do not support the "Intl" API.
+ return;
+ }
+
+ const selected = new Date(2017, SEP, 1);
testComponent.date = selected;
fixture.detectChanges();
fixture.whenStable().then(() => {
fixture.detectChanges();
- expect(input.value).toBe('01.09.2017');
+
+ // Normally the proper date format would 01.09.2017, but some browsers seem format the
+ // date without the leading zero. (e.g. 1.9.2017).
+ expect(input.value).toMatch(/0?1\.0?9\.2017/);
+
expect(testComponent.datepickerInput.value).toBe(selected);
});
- });
+ }));
});
});
@@ -1096,10 +1114,11 @@ describe('MatDatepicker', () => {
@Component({
template: `
-
+
`,
})
class StandardDatepicker {
+ opened = false;
touch = false;
disabled = false;
date: Date | null = new Date(2020, JAN, 1);
diff --git a/src/lib/datepicker/datepicker.ts b/src/lib/datepicker/datepicker.ts
index ae0bd02aab63..910baac9b011 100644
--- a/src/lib/datepicker/datepicker.ts
+++ b/src/lib/datepicker/datepicker.ts
@@ -186,7 +186,10 @@ export class MatDatepicker implements OnDestroy {
@Output('closed') closedStream: EventEmitter = new EventEmitter();
/** Whether the calendar is open. */
- opened = false;
+ @Input()
+ get opened(): boolean { return this._opened; }
+ set opened(shouldOpen: boolean) { shouldOpen ? this.open() : this.close(); }
+ private _opened = false;
/** The id for the datepicker calendar. */
id = `mat-datepicker-${datepickerUid++}`;
@@ -277,7 +280,7 @@ export class MatDatepicker implements OnDestroy {
/** Open the calendar. */
open(): void {
- if (this.opened || this.disabled) {
+ if (this._opened || this.disabled) {
return;
}
if (!this._datepickerInput) {
@@ -288,13 +291,13 @@ export class MatDatepicker implements OnDestroy {
}
this.touchUi ? this._openAsDialog() : this._openAsPopup();
- this.opened = true;
+ this._opened = true;
this.openedStream.emit();
}
/** Close the calendar. */
close(): void {
- if (!this.opened) {
+ if (!this._opened) {
return;
}
if (this._popupRef && this._popupRef.hasAttached()) {
@@ -314,7 +317,7 @@ export class MatDatepicker implements OnDestroy {
this._focusedElementBeforeOpen = null;
}
- this.opened = false;
+ this._opened = false;
this.closedStream.emit();
}