Skip to content

Commit 2b9bc57

Browse files
devversiontinayuangao
authored andcommitted
feat(datepicker): add opened input binding (#8098)
* Adds support for the `opened` input binding. Closes #8094
1 parent 9e35bf0 commit 2b9bc57

File tree

2 files changed

+57
-35
lines changed

2 files changed

+57
-35
lines changed

src/lib/datepicker/datepicker.spec.ts

Lines changed: 49 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ import {MatDatepickerInput} from './datepicker-input';
2828
import {MatDatepickerToggle} from './datepicker-toggle';
2929
import {MatDatepickerIntl, MatDatepickerModule} from './index';
3030

31-
3231
describe('MatDatepicker', () => {
3332
const SUPPORTS_INTL = typeof Intl != 'undefined';
3433

@@ -113,6 +112,18 @@ describe('MatDatepicker', () => {
113112
.not.toBeNull();
114113
});
115114

115+
it('should open datepicker if opened input is set to true', () => {
116+
testComponent.opened = true;
117+
fixture.detectChanges();
118+
119+
expect(document.querySelector('.mat-datepicker-content')).not.toBeNull();
120+
121+
testComponent.opened = false;
122+
fixture.detectChanges();
123+
124+
expect(document.querySelector('.mat-datepicker-content')).toBeNull();
125+
});
126+
116127
it('open in disabled mode should not open the calendar', () => {
117128
testComponent.disabled = true;
118129
fixture.detectChanges();
@@ -151,9 +162,7 @@ describe('MatDatepicker', () => {
151162
testComponent.datepicker.close();
152163
fixture.detectChanges();
153164

154-
fixture.whenStable().then(() => {
155-
expect(parseInt(getComputedStyle(popup).height as string)).toBe(0);
156-
});
165+
expect(parseInt(getComputedStyle(popup).height as string)).toBe(0);
157166
});
158167

159168
it('should close the popup when pressing ESCAPE', () => {
@@ -177,7 +186,7 @@ describe('MatDatepicker', () => {
177186
.toBe(true, 'Expected default ESCAPE action to be prevented.');
178187
});
179188

180-
it('close should close dialog', () => {
189+
it('close should close dialog', async(() => {
181190
testComponent.touch = true;
182191
fixture.detectChanges();
183192

@@ -192,9 +201,9 @@ describe('MatDatepicker', () => {
192201
fixture.whenStable().then(() => {
193202
expect(document.querySelector('mat-dialog-container')).toBeNull();
194203
});
195-
});
204+
}));
196205

197-
it('setting selected should update input and close calendar', () => {
206+
it('setting selected should update input and close calendar', async(() => {
198207
testComponent.touch = true;
199208
fixture.detectChanges();
200209

@@ -212,12 +221,13 @@ describe('MatDatepicker', () => {
212221
expect(document.querySelector('mat-dialog-container')).toBeNull();
213222
expect(testComponent.datepickerInput.value).toEqual(new Date(2020, JAN, 2));
214223
});
215-
});
224+
}));
216225

217226
it('clicking the currently selected date should close the calendar ' +
218227
'without firing selectedChanged', () => {
219228
const selectedChangedSpy =
220229
spyOn(testComponent.datepicker.selectedChanged, 'emit').and.callThrough();
230+
221231
for (let changeCount = 1; changeCount < 3; changeCount++) {
222232
const currentDay = changeCount;
223233
testComponent.datepicker.open();
@@ -231,11 +241,9 @@ describe('MatDatepicker', () => {
231241
fixture.detectChanges();
232242
}
233243

234-
fixture.whenStable().then(() => {
235-
expect(selectedChangedSpy.calls.count()).toEqual(1);
236-
expect(document.querySelector('mat-dialog-container')).toBeNull();
237-
expect(testComponent.datepickerInput.value).toEqual(new Date(2020, JAN, 2));
238-
});
244+
expect(selectedChangedSpy.calls.count()).toEqual(1);
245+
expect(document.querySelector('mat-dialog-container')).toBeNull();
246+
expect(testComponent.datepickerInput.value).toEqual(new Date(2020, JAN, 2));
239247
});
240248

241249
it('startAt should fallback to input value', () => {
@@ -479,7 +487,7 @@ describe('MatDatepicker', () => {
479487
expect(inputEl.classList).toContain('ng-touched');
480488
});
481489

482-
it('should mark input touched on calendar selection', () => {
490+
it('should mark input touched on calendar selection', async(() => {
483491
let inputEl = fixture.debugElement.query(By.css('input')).nativeElement;
484492

485493
expect(inputEl.classList).toContain('ng-untouched');
@@ -492,7 +500,7 @@ describe('MatDatepicker', () => {
492500

493501
expect(inputEl.classList).toContain('ng-touched');
494502
});
495-
});
503+
}));
496504
});
497505

498506
describe('datepicker with formControl', () => {
@@ -702,7 +710,7 @@ describe('MatDatepicker', () => {
702710
expect(testComponent.datepicker._maxDate).toEqual(new Date(2020, JAN, 1));
703711
});
704712

705-
it('should mark invalid when value is before min', () => {
713+
it('should mark invalid when value is before min', async(() => {
706714
testComponent.date = new Date(2009, DEC, 31);
707715
fixture.detectChanges();
708716

@@ -712,9 +720,9 @@ describe('MatDatepicker', () => {
712720
expect(fixture.debugElement.query(By.css('input')).nativeElement.classList)
713721
.toContain('ng-invalid');
714722
});
715-
});
723+
}));
716724

717-
it('should mark invalid when value is after max', () => {
725+
it('should mark invalid when value is after max', async(() => {
718726
testComponent.date = new Date(2020, JAN, 2);
719727
fixture.detectChanges();
720728

@@ -724,9 +732,9 @@ describe('MatDatepicker', () => {
724732
expect(fixture.debugElement.query(By.css('input')).nativeElement.classList)
725733
.toContain('ng-invalid');
726734
});
727-
});
735+
}));
728736

729-
it('should not mark invalid when value equals min', () => {
737+
it('should not mark invalid when value equals min', async(() => {
730738
testComponent.date = testComponent.datepicker._minDate;
731739
fixture.detectChanges();
732740

@@ -736,9 +744,9 @@ describe('MatDatepicker', () => {
736744
expect(fixture.debugElement.query(By.css('input')).nativeElement.classList)
737745
.not.toContain('ng-invalid');
738746
});
739-
});
747+
}));
740748

741-
it('should not mark invalid when value equals max', () => {
749+
it('should not mark invalid when value equals max', async(() => {
742750
testComponent.date = testComponent.datepicker._maxDate;
743751
fixture.detectChanges();
744752

@@ -748,9 +756,9 @@ describe('MatDatepicker', () => {
748756
expect(fixture.debugElement.query(By.css('input')).nativeElement.classList)
749757
.not.toContain('ng-invalid');
750758
});
751-
});
759+
}));
752760

753-
it('should not mark invalid when value is between min and max', () => {
761+
it('should not mark invalid when value is between min and max', async(() => {
754762
testComponent.date = new Date(2010, JAN, 2);
755763
fixture.detectChanges();
756764

@@ -760,7 +768,7 @@ describe('MatDatepicker', () => {
760768
expect(fixture.debugElement.query(By.css('input')).nativeElement.classList)
761769
.not.toContain('ng-invalid');
762770
});
763-
});
771+
}));
764772
});
765773

766774
describe('datepicker with filter and validation', () => {
@@ -1078,28 +1086,39 @@ describe('MatDatepicker', () => {
10781086
input = fixture.nativeElement.querySelector('input') as HTMLInputElement;
10791087
}));
10801088

1081-
it('should have the correct input value even when inverted date format', () => {
1082-
let selected = new Date(2017, SEP, 1);
1089+
it('should have the correct input value even when inverted date format', async(() => {
1090+
if (typeof Intl === 'undefined') {
1091+
// Skip this test if the internationalization API is not supported in the current
1092+
// browser. Browsers like Safari 9 do not support the "Intl" API.
1093+
return;
1094+
}
1095+
1096+
const selected = new Date(2017, SEP, 1);
10831097
testComponent.date = selected;
10841098
fixture.detectChanges();
10851099

10861100
fixture.whenStable().then(() => {
10871101
fixture.detectChanges();
1088-
expect(input.value).toBe('01.09.2017');
1102+
1103+
// Normally the proper date format would 01.09.2017, but some browsers seem format the
1104+
// date without the leading zero. (e.g. 1.9.2017).
1105+
expect(input.value).toMatch(/0?1\.0?9\.2017/);
1106+
10891107
expect(testComponent.datepickerInput.value).toBe(selected);
10901108
});
1091-
});
1109+
}));
10921110
});
10931111
});
10941112

10951113

10961114
@Component({
10971115
template: `
10981116
<input [matDatepicker]="d" [value]="date">
1099-
<mat-datepicker #d [touchUi]="touch" [disabled]="disabled"></mat-datepicker>
1117+
<mat-datepicker #d [touchUi]="touch" [disabled]="disabled" [opened]="opened"></mat-datepicker>
11001118
`,
11011119
})
11021120
class StandardDatepicker {
1121+
opened = false;
11031122
touch = false;
11041123
disabled = false;
11051124
date: Date | null = new Date(2020, JAN, 1);

src/lib/datepicker/datepicker.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,10 @@ export class MatDatepicker<D> implements OnDestroy {
186186
@Output('closed') closedStream: EventEmitter<void> = new EventEmitter<void>();
187187

188188
/** Whether the calendar is open. */
189-
opened = false;
189+
@Input()
190+
get opened(): boolean { return this._opened; }
191+
set opened(shouldOpen: boolean) { shouldOpen ? this.open() : this.close(); }
192+
private _opened = false;
190193

191194
/** The id for the datepicker calendar. */
192195
id = `mat-datepicker-${datepickerUid++}`;
@@ -277,7 +280,7 @@ export class MatDatepicker<D> implements OnDestroy {
277280

278281
/** Open the calendar. */
279282
open(): void {
280-
if (this.opened || this.disabled) {
283+
if (this._opened || this.disabled) {
281284
return;
282285
}
283286
if (!this._datepickerInput) {
@@ -288,13 +291,13 @@ export class MatDatepicker<D> implements OnDestroy {
288291
}
289292

290293
this.touchUi ? this._openAsDialog() : this._openAsPopup();
291-
this.opened = true;
294+
this._opened = true;
292295
this.openedStream.emit();
293296
}
294297

295298
/** Close the calendar. */
296299
close(): void {
297-
if (!this.opened) {
300+
if (!this._opened) {
298301
return;
299302
}
300303
if (this._popupRef && this._popupRef.hasAttached()) {
@@ -314,7 +317,7 @@ export class MatDatepicker<D> implements OnDestroy {
314317
this._focusedElementBeforeOpen = null;
315318
}
316319

317-
this.opened = false;
320+
this._opened = false;
318321
this.closedStream.emit();
319322
}
320323

0 commit comments

Comments
 (0)