mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
fix(autocomplete): panel not closing on IE when selecting an option with an empty string display value (#9506)
Fixes the autocomplete panel reopening on IE11 when the user selects an option whose display value is an empty string. Fixes #9479.
This commit is contained in:
committed by
tinayuangao
parent
e30852aa4c
commit
95ffe371b1
@@ -121,6 +121,9 @@ export class MatAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
|
||||
private _portal: TemplatePortal;
|
||||
private _componentDestroyed = false;
|
||||
|
||||
/** Old value of the native input. Used to work around issues with the `input` event on IE. */
|
||||
private _previousValue: string | number | null;
|
||||
|
||||
/** Strategy that is used to position the panel. */
|
||||
private _positionStrategy: ConnectedPositionStrategy;
|
||||
|
||||
@@ -301,18 +304,22 @@ export class MatAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
|
||||
}
|
||||
|
||||
_handleInput(event: KeyboardEvent): void {
|
||||
// We need to ensure that the input is focused, because IE will fire the `input`
|
||||
// event on focus/blur/load if the input has a placeholder. See:
|
||||
// https://connect.microsoft.com/IE/feedback/details/885747/
|
||||
if (this._canOpen() && document.activeElement === event.target) {
|
||||
let target = event.target as HTMLInputElement;
|
||||
let value: number | string | null = target.value;
|
||||
let target = event.target as HTMLInputElement;
|
||||
let value: number | string | null = target.value;
|
||||
|
||||
// Based on `NumberValueAccessor` from forms.
|
||||
if (target.type === 'number') {
|
||||
value = value == '' ? null : parseFloat(value);
|
||||
}
|
||||
// Based on `NumberValueAccessor` from forms.
|
||||
if (target.type === 'number') {
|
||||
value = value == '' ? null : parseFloat(value);
|
||||
}
|
||||
|
||||
// If the input has a placeholder, IE will fire the `input` event on page load,
|
||||
// focus and blur, in addition to when the user actually changed the value. To
|
||||
// filter out all of the extra events, we save the value on focus and between
|
||||
// `input` events, and we check whether it changed.
|
||||
// See: https://connect.microsoft.com/IE/feedback/details/885747/
|
||||
if (this._canOpen() && this._previousValue !== value &&
|
||||
document.activeElement === event.target) {
|
||||
this._previousValue = value;
|
||||
this._onChange(value);
|
||||
this.openPanel();
|
||||
}
|
||||
@@ -320,6 +327,7 @@ export class MatAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
|
||||
|
||||
_handleFocus(): void {
|
||||
if (this._canOpen()) {
|
||||
this._previousValue = this._element.nativeElement.value;
|
||||
this._attachOverlay();
|
||||
this._floatLabel(true);
|
||||
}
|
||||
|
||||
@@ -234,6 +234,7 @@ describe('MatAutocomplete', () => {
|
||||
|
||||
// Changing value from 'Alabama' to 'al' to re-populate the option list,
|
||||
// ensuring that 'California' is created new.
|
||||
dispatchFakeEvent(input, 'focusin');
|
||||
typeInElement('al', input);
|
||||
fixture.detectChanges();
|
||||
tick();
|
||||
@@ -818,6 +819,7 @@ describe('MatAutocomplete', () => {
|
||||
expect(overlayContainerElement.textContent)
|
||||
.toEqual('', `Expected panel to close after ENTER key.`);
|
||||
|
||||
dispatchFakeEvent(input, 'focusin');
|
||||
typeInElement('Alabama', input);
|
||||
fixture.detectChanges();
|
||||
tick();
|
||||
@@ -828,6 +830,31 @@ describe('MatAutocomplete', () => {
|
||||
.toContain('Alabama', `Expected panel to display when typing in input.`);
|
||||
}));
|
||||
|
||||
it('should not open the panel if the `input` event was dispatched with changing the value',
|
||||
fakeAsync(() => {
|
||||
const trigger = fixture.componentInstance.trigger;
|
||||
|
||||
dispatchFakeEvent(input, 'focusin');
|
||||
typeInElement('A', input);
|
||||
fixture.detectChanges();
|
||||
tick();
|
||||
|
||||
expect(trigger.panelOpen).toBe(true, 'Expected panel to be open.');
|
||||
|
||||
trigger.closePanel();
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(trigger.panelOpen).toBe(false, 'Expected panel to be closed.');
|
||||
|
||||
// Dispatch the event without actually changing the value
|
||||
// to simulate what happen in some cases on IE.
|
||||
dispatchFakeEvent(input, 'input');
|
||||
fixture.detectChanges();
|
||||
tick();
|
||||
|
||||
expect(trigger.panelOpen).toBe(false, 'Expected panel to stay closed.');
|
||||
}));
|
||||
|
||||
it('should scroll to active options below the fold', () => {
|
||||
const trigger = fixture.componentInstance.trigger;
|
||||
const scrollContainer =
|
||||
|
||||
Reference in New Issue
Block a user