mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
fix(autocomplete): emit closing action for escape keydown event (#6250)
This commit is contained in:
@@ -38,6 +38,7 @@ import {MatOption, MatOptionSelectionChange} from '@angular/material/core';
|
||||
import {MatFormField} from '@angular/material/form-field';
|
||||
import {DOCUMENT} from '@angular/platform-browser';
|
||||
import {Observable} from 'rxjs/Observable';
|
||||
import {Subject} from 'rxjs/Subject';
|
||||
import {fromEvent} from 'rxjs/observable/fromEvent';
|
||||
import {merge} from 'rxjs/observable/merge';
|
||||
import {of as observableOf} from 'rxjs/observable/of';
|
||||
@@ -125,6 +126,9 @@ export class MatAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
|
||||
/** The subscription for closing actions (some are bound to document). */
|
||||
private _closingActionsSubscription: Subscription;
|
||||
|
||||
/** Stream of escape keyboard events. */
|
||||
private _escapeEventStream = new Subject<void>();
|
||||
|
||||
/** View -> model callback called when value changes */
|
||||
_onChange: (value: any) => void = () => {};
|
||||
|
||||
@@ -145,6 +149,7 @@ export class MatAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
|
||||
|
||||
ngOnDestroy() {
|
||||
this._destroyPanel();
|
||||
this._escapeEventStream.complete();
|
||||
}
|
||||
|
||||
/* Whether or not the autocomplete panel is open. */
|
||||
@@ -186,6 +191,7 @@ export class MatAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
|
||||
return merge(
|
||||
this.optionSelections,
|
||||
this.autocomplete._keyManager.tabOut,
|
||||
this._escapeEventStream,
|
||||
this._outsideClickStream
|
||||
);
|
||||
}
|
||||
@@ -262,7 +268,7 @@ export class MatAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
|
||||
|
||||
if (keyCode === ESCAPE && this.panelOpen) {
|
||||
this._resetActiveItem();
|
||||
this.closePanel();
|
||||
this._escapeEventStream.next();
|
||||
event.stopPropagation();
|
||||
} else if (this.activeOption && keyCode === ENTER && this.panelOpen) {
|
||||
this.activeOption._selectViaInteraction();
|
||||
|
||||
@@ -1403,6 +1403,71 @@ describe('MatAutocomplete', () => {
|
||||
}));
|
||||
});
|
||||
|
||||
describe('panel closing', () => {
|
||||
let fixture: ComponentFixture<SimpleAutocomplete>;
|
||||
let input: HTMLInputElement;
|
||||
let trigger: MatAutocompleteTrigger;
|
||||
let closingActionSpy: jasmine.Spy;
|
||||
let closingActionsSub: Subscription;
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(SimpleAutocomplete);
|
||||
fixture.detectChanges();
|
||||
|
||||
input = fixture.debugElement.query(By.css('input')).nativeElement;
|
||||
|
||||
fixture.componentInstance.trigger.openPanel();
|
||||
fixture.detectChanges();
|
||||
|
||||
trigger = fixture.componentInstance.trigger;
|
||||
closingActionSpy = jasmine.createSpy('closing action listener');
|
||||
closingActionsSub = trigger.panelClosingActions.subscribe(closingActionSpy);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
closingActionsSub.unsubscribe();
|
||||
});
|
||||
|
||||
it('should emit panel close event when clicking away', async(() => {
|
||||
fixture.whenStable().then(() => {
|
||||
expect(closingActionSpy).not.toHaveBeenCalled();
|
||||
dispatchFakeEvent(document, 'click');
|
||||
expect(closingActionSpy).toHaveBeenCalled();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should emit panel close event when tabbing out', async(() => {
|
||||
const tabEvent = createKeyboardEvent('keydown', TAB);
|
||||
input.focus();
|
||||
|
||||
fixture.whenStable().then(() => {
|
||||
expect(closingActionSpy).not.toHaveBeenCalled();
|
||||
trigger._handleKeydown(tabEvent);
|
||||
expect(closingActionSpy).toHaveBeenCalled();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should emit panel close event when selecting an option', async(() => {
|
||||
fixture.whenStable().then(() => {
|
||||
const option = overlayContainerElement.querySelector('mat-option') as HTMLElement;
|
||||
|
||||
expect(closingActionSpy).not.toHaveBeenCalled();
|
||||
option.click();
|
||||
expect(closingActionSpy).toHaveBeenCalled();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should close the panel when pressing escape', async(() => {
|
||||
const escapeEvent = createKeyboardEvent('keydown', ESCAPE);
|
||||
|
||||
fixture.whenStable().then(() => {
|
||||
expect(closingActionSpy).not.toHaveBeenCalled();
|
||||
trigger._handleKeydown(escapeEvent);
|
||||
expect(closingActionSpy).toHaveBeenCalled();
|
||||
});
|
||||
}));
|
||||
});
|
||||
|
||||
describe('without matInput', () => {
|
||||
let fixture: ComponentFixture<AutocompleteWithNativeInput>;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user