Skip to content

Commit 0ce3d7b

Browse files
committed
fix(autocomplete): optionSelections not emitting when the list of options changes
Fixes the `MatAutocompleteTrigger.optionSelections` stopping to emit when the list options has been swapped out. Fixes #14777.
1 parent f9ebb26 commit 0ce3d7b

File tree

2 files changed

+38
-5
lines changed

2 files changed

+38
-5
lines changed

src/material/autocomplete/autocomplete-trigger.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import {
1818
} from '@angular/cdk/overlay';
1919
import {TemplatePortal} from '@angular/cdk/portal';
2020
import {DOCUMENT} from '@angular/common';
21-
import {filter, take, switchMap, delay, tap, map} from 'rxjs/operators';
21+
import {filter, take, switchMap, delay, tap, map, startWith} from 'rxjs/operators';
2222
import {
2323
ChangeDetectorRef,
2424
Directive,
@@ -316,10 +316,15 @@ export class MatAutocompleteTrigger implements ControlValueAccessor, OnChanges,
316316
);
317317
}
318318

319-
/** Stream of autocomplete option selections. */
319+
/** Stream of changes to the selection state of the autocomplete options. */
320320
readonly optionSelections: Observable<MatOptionSelectionChange> = defer(() => {
321-
if (this.autocomplete && this.autocomplete.options) {
322-
return merge(...this.autocomplete.options.map(option => option.onSelectionChange));
321+
const options = this.autocomplete ? this.autocomplete.options : null;
322+
323+
if (options) {
324+
return options.changes.pipe(
325+
startWith(options),
326+
switchMap(() => merge(...options.map(option => option.onSelectionChange)))
327+
);
323328
}
324329

325330
// If there are any subscribers before `ngAfterViewInit`, the `autocomplete` will be undefined.
@@ -358,7 +363,7 @@ export class MatAutocompleteTrigger implements ControlValueAccessor, OnChanges,
358363

359364
// Implemented as part of ControlValueAccessor.
360365
writeValue(value: any): void {
361-
Promise.resolve(null).then(() => this._setTriggerValue(value));
366+
Promise.resolve().then(() => this._setTriggerValue(value));
362367
}
363368

364369
// Implemented as part of ControlValueAccessor.

src/material/autocomplete/autocomplete.spec.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1835,6 +1835,34 @@ describe('MatAutocomplete', () => {
18351835
subscription!.unsubscribe();
18361836
}));
18371837

1838+
it('should emit to `optionSelections` if the list of options changes', fakeAsync(() => {
1839+
const spy = jasmine.createSpy('option selection spy');
1840+
const subscription = fixture.componentInstance.trigger.optionSelections.subscribe(spy);
1841+
const openAndSelectFirstOption = () => {
1842+
fixture.detectChanges();
1843+
fixture.componentInstance.trigger.openPanel();
1844+
fixture.detectChanges();
1845+
zone.simulateZoneExit();
1846+
(overlayContainerElement.querySelector('mat-option') as HTMLElement).click();
1847+
fixture.detectChanges();
1848+
zone.simulateZoneExit();
1849+
};
1850+
1851+
fixture.componentInstance.states = [{code: 'OR', name: 'Oregon'}];
1852+
fixture.detectChanges();
1853+
1854+
openAndSelectFirstOption();
1855+
expect(spy).toHaveBeenCalledTimes(1);
1856+
1857+
fixture.componentInstance.states = [{code: 'WV', name: 'West Virginia'}];
1858+
fixture.detectChanges();
1859+
1860+
openAndSelectFirstOption();
1861+
expect(spy).toHaveBeenCalledTimes(2);
1862+
1863+
subscription!.unsubscribe();
1864+
}));
1865+
18381866
it('should reposition the panel when the amount of options changes', fakeAsync(() => {
18391867
let formField = fixture.debugElement.query(By.css('.mat-form-field')).nativeElement;
18401868
let inputReference = formField.querySelector('.mat-form-field-flex');

0 commit comments

Comments
 (0)