Skip to content

Commit 47088f6

Browse files
committed
fix(autocomplete): emit closing action for escape keydown event
1 parent 79a2567 commit 47088f6

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
@@ -25,7 +25,7 @@ import {
2525
} from './index';
2626
import {MdInputModule} from '../input/index';
2727
import {Subscription} from 'rxjs/Subscription';
28-
import {DOWN_ARROW, ENTER, ESCAPE, SPACE, UP_ARROW} from '../core/keyboard/keycodes';
28+
import {DOWN_ARROW, ENTER, ESCAPE, SPACE, TAB, UP_ARROW} from '../core/keyboard/keycodes';
2929
import {MdOption} from '../core/option/option';
3030
import {MdFormField, MdFormFieldModule} from '../form-field/index';
3131
import {Observable} from 'rxjs/Observable';
@@ -1359,6 +1359,71 @@ describe('MdAutocomplete', () => {
13591359
}));
13601360
});
13611361

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

0 commit comments

Comments
 (0)