Skip to content

Commit

Permalink
fix(datepicker): not resetting when detached externally (#9133)
Browse files Browse the repository at this point in the history
Fixes not being able to reopen a datepicker if it's detached via the `OverlayRef` (e.g. by a `CloseScrollStrategy`).
  • Loading branch information
crisbeto authored and jelbourn committed Jan 4, 2018
1 parent b0449ab commit a0bd162
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 9 deletions.
49 changes: 44 additions & 5 deletions src/lib/datepicker/datepicker.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {ENTER, ESCAPE, RIGHT_ARROW} from '@angular/cdk/keycodes';
import {OverlayContainer} from '@angular/cdk/overlay';
import {OverlayContainer, Overlay, ScrollDispatcher} from '@angular/cdk/overlay';
import {
createKeyboardEvent,
dispatchEvent,
Expand Down Expand Up @@ -27,7 +27,8 @@ import {MatInputModule} from '../input/index';
import {MatDatepicker} from './datepicker';
import {MatDatepickerInput} from './datepicker-input';
import {MatDatepickerToggle} from './datepicker-toggle';
import {MatDatepickerIntl, MatDatepickerModule} from './index';
import {MatDatepickerIntl, MatDatepickerModule, MAT_DATEPICKER_SCROLL_STRATEGY} from './index';
import {Subject} from 'rxjs/Subject';

describe('MatDatepicker', () => {
const SUPPORTS_INTL = typeof Intl != 'undefined';
Expand Down Expand Up @@ -342,17 +343,55 @@ describe('MatDatepicker', () => {
testComponent.datepicker.open();
fixture.detectChanges();

spyOn(testComponent.datepicker, 'close').and.callThrough();

const spy = jasmine.createSpy('close event spy');
const subscription = testComponent.datepicker.closedStream.subscribe(spy);
const backdrop = document.querySelector('.cdk-overlay-backdrop')! as HTMLElement;

backdrop.click();
fixture.detectChanges();
flush();

expect(testComponent.datepicker.close).toHaveBeenCalledTimes(1);
expect(spy).toHaveBeenCalledTimes(1);
expect(testComponent.datepicker.opened).toBe(false);
subscription.unsubscribe();
}));

it('should reset the datepicker when it is closed externally',
fakeAsync(inject([OverlayContainer], (oldOverlayContainer: OverlayContainer) => {

// Destroy the old container manually since resetting the testing module won't do it.
oldOverlayContainer.ngOnDestroy();
TestBed.resetTestingModule();

const scrolledSubject = new Subject();

// Stub out a `CloseScrollStrategy` so we can trigger a detachment via the `OverlayRef`.
fixture = createComponent(StandardDatepicker, [MatNativeDateModule], [
{
provide: ScrollDispatcher,
useValue: {scrolled: () => scrolledSubject}
},
{
provide: MAT_DATEPICKER_SCROLL_STRATEGY,
deps: [Overlay],
useFactory: (overlay: Overlay) => () => overlay.scrollStrategies.close()
}
]);

fixture.detectChanges();
testComponent = fixture.componentInstance;

testComponent.datepicker.open();
fixture.detectChanges();

expect(testComponent.datepicker.opened).toBe(true);

scrolledSubject.next();
flush();
fixture.detectChanges();

expect(testComponent.datepicker.opened).toBe(false);
})));
});

describe('datepicker with too many inputs', () => {
Expand Down
15 changes: 11 additions & 4 deletions src/lib/datepicker/datepicker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import {MatDialog, MatDialogRef} from '@angular/material/dialog';
import {DOCUMENT} from '@angular/common';
import {Subject} from 'rxjs/Subject';
import {Subscription} from 'rxjs/Subscription';
import {merge} from 'rxjs/observable/merge';
import {MatCalendar} from './calendar';
import {createMissingDateImplError} from './datepicker-errors';
import {MatDatepickerInput} from './datepicker-input';
Expand Down Expand Up @@ -312,9 +313,13 @@ export class MatDatepicker<D> implements OnDestroy {
}

const completeClose = () => {
this._opened = false;
this.closedStream.emit();
this._focusedElementBeforeOpen = null;
// The `_opened` could've been reset already if
// we got two events in quick succession.
if (this._opened) {
this._opened = false;
this.closedStream.emit();
this._focusedElementBeforeOpen = null;
}
};

if (this._focusedElementBeforeOpen &&
Expand Down Expand Up @@ -376,7 +381,9 @@ export class MatDatepicker<D> implements OnDestroy {
});

this._popupRef = this._overlay.create(overlayConfig);
this._popupRef.backdropClick().subscribe(() => this.close());

merge(this._popupRef.backdropClick(), this._popupRef.detachments())
.subscribe(() => this.close());
}

/** Create the popup PositionStrategy. */
Expand Down

0 comments on commit a0bd162

Please # to comment.