Skip to content

feat(datepicker): add opened input binding #8098

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 29, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 49 additions & 30 deletions src/lib/datepicker/datepicker.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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', () => {
Expand All @@ -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();

Expand All @@ -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();

Expand All @@ -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();
Expand All @@ -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', () => {
Expand Down Expand Up @@ -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');
Expand All @@ -492,7 +500,7 @@ describe('MatDatepicker', () => {

expect(inputEl.classList).toContain('ng-touched');
});
});
}));
});

describe('datepicker with formControl', () => {
Expand Down Expand Up @@ -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();

Expand All @@ -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();

Expand All @@ -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();

Expand All @@ -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();

Expand All @@ -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();

Expand All @@ -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', () => {
Expand Down Expand Up @@ -1078,28 +1086,39 @@ 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);
});
});
}));
});
});


@Component({
template: `
<input [matDatepicker]="d" [value]="date">
<mat-datepicker #d [touchUi]="touch" [disabled]="disabled"></mat-datepicker>
<mat-datepicker #d [touchUi]="touch" [disabled]="disabled" [opened]="opened"></mat-datepicker>
`,
})
class StandardDatepicker {
opened = false;
touch = false;
disabled = false;
date: Date | null = new Date(2020, JAN, 1);
Expand Down
13 changes: 8 additions & 5 deletions src/lib/datepicker/datepicker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,10 @@ export class MatDatepicker<D> implements OnDestroy {
@Output('closed') closedStream: EventEmitter<void> = new EventEmitter<void>();

/** 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++}`;
Expand Down Expand Up @@ -277,7 +280,7 @@ export class MatDatepicker<D> implements OnDestroy {

/** Open the calendar. */
open(): void {
if (this.opened || this.disabled) {
if (this._opened || this.disabled) {
return;
}
if (!this._datepickerInput) {
Expand All @@ -288,13 +291,13 @@ export class MatDatepicker<D> 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()) {
Expand All @@ -314,7 +317,7 @@ export class MatDatepicker<D> implements OnDestroy {
this._focusedElementBeforeOpen = null;
}

this.opened = false;
this._opened = false;
this.closedStream.emit();
}

Expand Down