diff --git a/src/material-experimental/mdc-autocomplete/autocomplete.spec.ts b/src/material-experimental/mdc-autocomplete/autocomplete.spec.ts index 621e2d69855e..5448cbd10c57 100644 --- a/src/material-experimental/mdc-autocomplete/autocomplete.spec.ts +++ b/src/material-experimental/mdc-autocomplete/autocomplete.spec.ts @@ -2256,6 +2256,32 @@ describe('MDC-based MatAutocomplete', () => { componentOptions.slice(1).forEach(option => expect(option.deselect).not.toHaveBeenCalled()); })); + it('should not reset the active item if the options list changes while open', fakeAsync(() => { + fixture.componentInstance.trigger.openPanel(); + fixture.detectChanges(); + zone.simulateZoneExit(); + fixture.detectChanges(); + + const DOWN_ARROW_EVENT = createKeyboardEvent('keydown', DOWN_ARROW); + fixture.componentInstance.trigger._handleKeydown(DOWN_ARROW_EVENT); + fixture.detectChanges(); + tick(); + + const classList = overlayContainerElement.querySelector('mat-option')!.classList; + expect(classList) + .withContext('Expected first option to be highlighted.') + .toContain('mat-mdc-option-active'); + + fixture.componentInstance.states.push({code: 'PR', name: 'Puerto Rico'}); + fixture.detectChanges(); + tick(); + fixture.detectChanges(); + + expect(classList) + .withContext('Expected first option to stay highlighted.') + .toContain('mat-mdc-option-active'); + })); + it('should be able to preselect the first option', fakeAsync(() => { fixture.componentInstance.trigger.autocomplete.autoActiveFirstOption = true; fixture.componentInstance.trigger.openPanel(); @@ -2276,6 +2302,7 @@ describe('MDC-based MatAutocomplete', () => { testComponent.trigger.autocomplete.autoActiveFirstOption = true; testComponent.states[0].disabled = true; testComponent.states[1].disabled = true; + fixture.detectChanges(); testComponent.trigger.openPanel(); fixture.detectChanges(); zone.simulateZoneExit(); diff --git a/src/material/autocomplete/autocomplete-trigger.ts b/src/material/autocomplete/autocomplete-trigger.ts index b9312e8d2aec..bca3b0371524 100644 --- a/src/material/autocomplete/autocomplete-trigger.ts +++ b/src/material/autocomplete/autocomplete-trigger.ts @@ -527,7 +527,6 @@ export abstract class _MatAutocompleteTriggerBase // that were created, and flatten it so our stream only emits closing events... switchMap(() => { const wasOpen = this.panelOpen; - this._resetActiveItem(); this.autocomplete._setVisibility(); this._changeDetectorRef.detectChanges(); @@ -539,6 +538,7 @@ export abstract class _MatAutocompleteTriggerBase // can happen if the users opens the panel and there are no options, but the // options come in slightly later or as a result of the value changing. if (wasOpen !== this.panelOpen) { + this._resetActiveItem(); this.autocomplete.opened.emit(); } } @@ -653,6 +653,7 @@ export abstract class _MatAutocompleteTriggerBase // We need to do an extra `panelOpen` check in here, because the // autocomplete won't be shown if there are no options. if (this.panelOpen && wasOpen !== this.panelOpen) { + this._resetActiveItem(); this.autocomplete.opened.emit(); } } diff --git a/src/material/autocomplete/autocomplete.spec.ts b/src/material/autocomplete/autocomplete.spec.ts index ed41c3acbceb..fba6246ccf4c 100644 --- a/src/material/autocomplete/autocomplete.spec.ts +++ b/src/material/autocomplete/autocomplete.spec.ts @@ -2241,6 +2241,32 @@ describe('MatAutocomplete', () => { componentOptions.slice(1).forEach(option => expect(option.deselect).not.toHaveBeenCalled()); })); + it('should not reset the active item if the options list changes while open', fakeAsync(() => { + fixture.componentInstance.trigger.openPanel(); + fixture.detectChanges(); + zone.simulateZoneExit(); + fixture.detectChanges(); + + const DOWN_ARROW_EVENT = createKeyboardEvent('keydown', DOWN_ARROW); + fixture.componentInstance.trigger._handleKeydown(DOWN_ARROW_EVENT); + fixture.detectChanges(); + tick(); + + const classList = overlayContainerElement.querySelector('mat-option')!.classList; + expect(classList) + .withContext('Expected first option to be highlighted.') + .toContain('mat-active'); + + fixture.componentInstance.states.push({code: 'PR', name: 'Puerto Rico'}); + fixture.detectChanges(); + tick(); + fixture.detectChanges(); + + expect(classList) + .withContext('Expected first option to stay highlighted.') + .toContain('mat-active'); + })); + it('should be able to preselect the first option', fakeAsync(() => { fixture.componentInstance.trigger.autocomplete.autoActiveFirstOption = true; fixture.componentInstance.trigger.openPanel(); @@ -2261,6 +2287,7 @@ describe('MatAutocomplete', () => { testComponent.trigger.autocomplete.autoActiveFirstOption = true; testComponent.states[0].disabled = true; testComponent.states[1].disabled = true; + fixture.detectChanges(); testComponent.trigger.openPanel(); fixture.detectChanges(); zone.simulateZoneExit();