Skip to content

Commit e100f6e

Browse files
committed
fix(autocomplete): handle escape key
* Closes the autocomplete panel when pressing escape. * Switches the autocomplete unit tests to using the common utility for creating fake keyboard events.
1 parent 0e24345 commit e100f6e

File tree

2 files changed

+52
-3
lines changed

2 files changed

+52
-3
lines changed

src/lib/autocomplete/autocomplete-trigger.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import {PositionStrategy} from '../core/overlay/position/position-strategy';
1919
import {ConnectedPositionStrategy} from '../core/overlay/position/connected-position-strategy';
2020
import {Observable} from 'rxjs/Observable';
2121
import {MdOptionSelectionChange, MdOption} from '../core/option/option';
22-
import {ENTER, UP_ARROW, DOWN_ARROW} from '../core/keyboard/keycodes';
22+
import {ENTER, UP_ARROW, DOWN_ARROW, ESCAPE} from '../core/keyboard/keycodes';
2323
import {Dir} from '../core/rtl/dir';
2424
import {MdInputContainer} from '../input/input-container';
2525
import {ScrollDispatcher} from '../core/overlay/scroll/scroll-dispatcher';
@@ -231,7 +231,9 @@ export class MdAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
231231
}
232232

233233
_handleKeydown(event: KeyboardEvent): void {
234-
if (this.activeOption && event.keyCode === ENTER) {
234+
if (event.keyCode === ESCAPE && this.panelOpen) {
235+
this.closePanel();
236+
} else if (this.activeOption && event.keyCode === ENTER) {
235237
this.activeOption._selectViaInteraction();
236238
event.preventDefault();
237239
} else {

src/lib/autocomplete/autocomplete.spec.ts

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import {MdInputModule} from '../input/index';
1616
import {Dir, LayoutDirection} from '../core/rtl/dir';
1717
import {FormControl, FormsModule, ReactiveFormsModule} from '@angular/forms';
1818
import {Subscription} from 'rxjs/Subscription';
19-
import {ENTER, DOWN_ARROW, SPACE, UP_ARROW} from '../core/keyboard/keycodes';
19+
import {ENTER, DOWN_ARROW, SPACE, UP_ARROW, HOME, END, ESCAPE} from '../core/keyboard/keycodes';
2020
import {MdOption} from '../core/option/option';
2121
import {MdAutocomplete} from './autocomplete';
2222
import {MdInputContainer} from '../input/input-container';
@@ -758,6 +758,53 @@ describe('MdAutocomplete', () => {
758758
expect(scrollContainer.scrollTop).toEqual(272, `Expected panel to reveal last option.`);
759759
}));
760760

761+
it('should scroll the active option into view when pressing END', fakeAsync(() => {
762+
tick();
763+
const scrollContainer =
764+
document.querySelector('.cdk-overlay-pane .mat-autocomplete-panel');
765+
766+
const END_EVENT = createKeyboardEvent('keydown', END);
767+
fixture.componentInstance.trigger._handleKeydown(END_EVENT);
768+
tick();
769+
fixture.detectChanges();
770+
771+
// Expect option bottom minus the panel height (528 - 256 = 272)
772+
expect(scrollContainer.scrollTop).toEqual(272, 'Expected panel to reveal the last option.');
773+
}));
774+
775+
it('should scroll the active option into view when pressing HOME', fakeAsync(() => {
776+
tick();
777+
const scrollContainer =
778+
document.querySelector('.cdk-overlay-pane .mat-autocomplete-panel');
779+
780+
scrollContainer.scrollTop = 100;
781+
fixture.detectChanges();
782+
783+
const HOME_EVENT = createKeyboardEvent('keydown', HOME);
784+
fixture.componentInstance.trigger._handleKeydown(HOME_EVENT);
785+
tick();
786+
fixture.detectChanges();
787+
788+
expect(scrollContainer.scrollTop).toEqual(0, 'Expected panel to reveal the first option.');
789+
}));
790+
791+
it('should close the panel when pressing escape', async(() => {
792+
const trigger = fixture.componentInstance.trigger;
793+
const escapeEvent = createKeyboardEvent('keydown', ESCAPE);
794+
795+
input.focus();
796+
797+
fixture.whenStable().then(() => {
798+
expect(document.activeElement).toBe(input, 'Expected input to be focused.');
799+
expect(trigger.panelOpen).toBe(true, 'Expected panel to be open.');
800+
801+
trigger._handleKeydown(escapeEvent);
802+
803+
expect(document.activeElement).toBe(input, 'Expected input to continue to be focused.');
804+
expect(trigger.panelOpen).toBe(false, 'Expected panel to be closed.');
805+
});
806+
}));
807+
761808
});
762809

763810
describe('aria', () => {

0 commit comments

Comments
 (0)