Skip to content

Commit 6d8da62

Browse files
committed
fix(autocomplete): emit closing action for escape keydown event
1 parent 595cffd commit 6d8da62

File tree

2 files changed

+72
-2
lines changed

2 files changed

+72
-2
lines changed

src/lib/autocomplete/autocomplete-trigger.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ import {TemplatePortal} from '@angular/cdk/portal';
4040
import {DOWN_ARROW, ENTER, ESCAPE, UP_ARROW} from '@angular/cdk/keycodes';
4141
import {Observable} from 'rxjs/Observable';
4242
import {MdFormField} from '../form-field/index';
43+
import {Subject} from 'rxjs/Subject';
4344
import {Subscription} from 'rxjs/Subscription';
4445
import {merge} from 'rxjs/observable/merge';
4546
import {fromEvent} from 'rxjs/observable/fromEvent';
@@ -130,6 +131,9 @@ export class MdAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
130131
/** The subscription for closing actions (some are bound to document). */
131132
private _closingActionsSubscription: Subscription;
132133

134+
/** Stream of escape keyboard events. */
135+
private _escapeEventStream = new Subject<KeyboardEvent>();
136+
133137
/** View -> model callback called when value changes */
134138
_onChange: (value: any) => void = () => {};
135139

@@ -201,6 +205,7 @@ export class MdAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
201205
return merge(
202206
this.optionSelections,
203207
this.autocomplete._keyManager.tabOut,
208+
this._escapeEventStream,
204209
this._outsideClickStream
205210
);
206211
}
@@ -275,7 +280,7 @@ export class MdAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
275280
_handleKeydown(event: KeyboardEvent): void {
276281
if (event.keyCode === ESCAPE && this.panelOpen) {
277282
this._resetActiveItem();
278-
this.closePanel();
283+
this._escapeEventStream.next(event);
279284
event.stopPropagation();
280285
} else if (this.activeOption && event.keyCode === ENTER && this.panelOpen) {
281286
this.activeOption._selectViaInteraction();

src/lib/autocomplete/autocomplete.spec.ts

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import {
2424
} from './index';
2525
import {MdInputModule} from '../input/index';
2626
import {Subscription} from 'rxjs/Subscription';
27-
import {DOWN_ARROW, ENTER, ESCAPE, SPACE, UP_ARROW} from '../core/keyboard/keycodes';
27+
import {DOWN_ARROW, ENTER, ESCAPE, SPACE, TAB, UP_ARROW} from '../core/keyboard/keycodes';
2828
import {MdOption} from '../core/option/option';
2929
import {MdFormField, MdFormFieldModule} from '../form-field/index';
3030
import {Observable} from 'rxjs/Observable';
@@ -1357,6 +1357,71 @@ describe('MdAutocomplete', () => {
13571357
}));
13581358
});
13591359

1360+
describe('panel closing', () => {
1361+
let fixture: ComponentFixture<SimpleAutocomplete>;
1362+
let input: HTMLInputElement;
1363+
let trigger: MdAutocompleteTrigger;
1364+
let closingActionSpy: jasmine.Spy;
1365+
let closingActionsSub: Subscription;
1366+
1367+
beforeEach(() => {
1368+
fixture = TestBed.createComponent(SimpleAutocomplete);
1369+
fixture.detectChanges();
1370+
1371+
input = fixture.debugElement.query(By.css('input')).nativeElement;
1372+
1373+
fixture.componentInstance.trigger.openPanel();
1374+
fixture.detectChanges();
1375+
1376+
trigger = fixture.componentInstance.trigger;
1377+
closingActionSpy = jasmine.createSpy('closing action listener');
1378+
closingActionsSub = trigger.panelClosingActions.subscribe(closingActionSpy);
1379+
});
1380+
1381+
afterEach(() => {
1382+
closingActionsSub.unsubscribe();
1383+
});
1384+
1385+
it('should emit panel close event when clicking away', async(() => {
1386+
fixture.whenStable().then(() => {
1387+
expect(closingActionSpy).not.toHaveBeenCalled();
1388+
dispatchFakeEvent(document, 'click');
1389+
expect(closingActionSpy).toHaveBeenCalled();
1390+
});
1391+
}));
1392+
1393+
it('should emit panel close event when tabbing out', async(() => {
1394+
const tabEvent = createKeyboardEvent('keydown', TAB);
1395+
input.focus();
1396+
1397+
fixture.whenStable().then(() => {
1398+
expect(closingActionSpy).not.toHaveBeenCalled();
1399+
trigger._handleKeydown(tabEvent);
1400+
expect(closingActionSpy).toHaveBeenCalled();
1401+
});
1402+
}));
1403+
1404+
it('should emit panel close event when selecting an option', async(() => {
1405+
fixture.whenStable().then(() => {
1406+
const option = overlayContainerElement.querySelector('md-option') as HTMLElement;
1407+
1408+
expect(closingActionSpy).not.toHaveBeenCalled();
1409+
option.click();
1410+
expect(closingActionSpy).toHaveBeenCalled();
1411+
});
1412+
}));
1413+
1414+
it('should close the panel when pressing escape', async(() => {
1415+
const escapeEvent = createKeyboardEvent('keydown', ESCAPE);
1416+
1417+
fixture.whenStable().then(() => {
1418+
expect(closingActionSpy).not.toHaveBeenCalled();
1419+
trigger._handleKeydown(escapeEvent);
1420+
expect(closingActionSpy).toHaveBeenCalled();
1421+
});
1422+
}));
1423+
});
1424+
13601425
describe('without mdInput', () => {
13611426
let fixture: ComponentFixture<AutocompleteWithNativeInput>;
13621427

0 commit comments

Comments
 (0)