Skip to content

Commit

Permalink
fix(autocomplete): handle optionSelections being accessed early
Browse files Browse the repository at this point in the history
Currently the `MatAutocompleteTrigger` will throw if `optionSelections` is accessed before `ngAfterViewInit`. These changes add a fallback stream that will be replaced once everything is initialized.

Fixes #4616.
  • Loading branch information
crisbeto committed Dec 6, 2017
1 parent 5210b3e commit 960d0d6
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 4 deletions.
15 changes: 12 additions & 3 deletions src/lib/autocomplete/autocomplete-trigger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import {MatFormField} from '@angular/material/form-field';
import {DOCUMENT} from '@angular/common';
import {Observable} from 'rxjs/Observable';
import {Subject} from 'rxjs/Subject';
import {defer} from 'rxjs/observable/defer';
import {fromEvent} from 'rxjs/observable/fromEvent';
import {merge} from 'rxjs/observable/merge';
import {of as observableOf} from 'rxjs/observable/of';
Expand Down Expand Up @@ -200,9 +201,17 @@ export class MatAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
}

/** Stream of autocomplete option selections. */
get optionSelections(): Observable<MatOptionSelectionChange> {
return merge(...this.autocomplete.options.map(option => option.onSelectionChange));
}
optionSelections = defer(() => {
if (this.autocomplete && this.autocomplete.options) {
return merge(...this.autocomplete.options.map(option => option.onSelectionChange));
}

// If there are any subscribers before `ngAfterViewInit`, the `autocomplete` will be undefined.
// Return a stream that we'll replace with the real one once everything is in place.
return this._zone.onStable
.asObservable()
.pipe(take(1), switchMap(() => this.optionSelections));
});

/** The currently active option, coerced to MatOption type. */
get activeOption(): MatOption | null {
Expand Down
38 changes: 37 additions & 1 deletion src/lib/autocomplete/autocomplete.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import {
} from '@angular/core';
import {async, ComponentFixture, fakeAsync, inject, TestBed, tick} from '@angular/core/testing';
import {FormControl, FormsModule, ReactiveFormsModule} from '@angular/forms';
import {MatOption} from '@angular/material/core';
import {MatOption, MatOptionSelectionChange} from '@angular/material/core';
import {MatFormField, MatFormFieldModule} from '@angular/material/form-field';
import {By} from '@angular/platform-browser';
import {NoopAnimationsModule} from '@angular/platform-browser/animations';
Expand Down Expand Up @@ -1324,6 +1324,42 @@ describe('MatAutocomplete', () => {
componentOptions.slice(1).forEach(option => expect(option.deselect).not.toHaveBeenCalled());
});
}));

it('should emit an event when an option is selected', fakeAsync(() => {
const spy = jasmine.createSpy('option selection spy');
const subscription = fixture.componentInstance.trigger.optionSelections.subscribe(spy);
const option = overlayContainerElement.querySelector('mat-option') as HTMLElement;
option.click();
fixture.detectChanges();

expect(spy).toHaveBeenCalledWith(jasmine.any(MatOptionSelectionChange));
}));

it('should handle `optionSelections` being accessed too early', async(() => {
fixture.destroy();
fixture = TestBed.createComponent(SimpleAutocomplete);

let spy = jasmine.createSpy('option selection spy');
let subscription: Subscription;

expect(fixture.componentInstance.trigger.autocomplete).toBeFalsy();
expect(() => {
subscription = fixture.componentInstance.trigger.optionSelections.subscribe(spy);
}).not.toThrow();

fixture.detectChanges();
fixture.componentInstance.trigger.openPanel();
fixture.detectChanges();

fixture.whenStable().then(() => {
const option = overlayContainerElement.querySelector('mat-option') as HTMLElement;
option.click();
fixture.detectChanges();

expect(spy).toHaveBeenCalledWith(jasmine.any(MatOptionSelectionChange));
});
}));

});

describe('panel closing', () => {
Expand Down

0 comments on commit 960d0d6

Please sign in to comment.