fix(autocomplete): throw better error when autocomplete doesn't have a panel (#4851)

Adds a more informative error if the user tries to open an autocomplete that doesn't exist or hasn't been defined yet by the `@ViewChild` query.

Fixes #4844.
This commit is contained in:
Kristiyan Kostadinov
2017-06-05 23:44:25 +02:00
committed by Andrew Seguin
parent 9d4a34accd
commit 70b31f177a
2 changed files with 41 additions and 6 deletions
+14 -1
View File
@@ -51,6 +51,15 @@ export const MD_AUTOCOMPLETE_VALUE_ACCESSOR: any = {
multi: true
};
/**
* Creates an error to be thrown when attempting to use an autocomplete trigger without a panel.
*/
export function getMdAutocompleteMissingPanelError(): Error {
return new Error('Attempting to open an undefined instance of `md-autocomplete`. ' +
'Make sure that the id passed to the `mdAutocomplete` is correct and that ' +
'you\'re attempting to open it after the ngAfterContentInit hook.');
}
@Directive({
selector: 'input[mdAutocomplete], input[matAutocomplete]',
host: {
@@ -124,6 +133,10 @@ export class MdAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
/** Opens the autocomplete suggestion panel. */
openPanel(): void {
if (!this.autocomplete) {
throw getMdAutocompleteMissingPanelError();
}
if (!this._overlayRef) {
this._createOverlay();
} else {
@@ -177,7 +190,7 @@ export class MdAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
/** The currently active option, coerced to MdOption type. */
get activeOption(): MdOption {
if (this.autocomplete._keyManager) {
if (this.autocomplete && this.autocomplete._keyManager) {
return this.autocomplete._keyManager.activeItem as MdOption;
}
}
+27 -5
View File
@@ -10,15 +10,19 @@ import {
} from '@angular/core';
import {By} from '@angular/platform-browser';
import {NoopAnimationsModule} from '@angular/platform-browser/animations';
import {MdAutocompleteModule, MdAutocompleteTrigger} from './index';
import {FormControl, FormsModule, ReactiveFormsModule} from '@angular/forms';
import {
MdAutocompleteModule,
MdAutocompleteTrigger,
MdAutocomplete,
getMdAutocompleteMissingPanelError,
} from './index';
import {OverlayContainer} from '../core/overlay/overlay-container';
import {MdInputModule} from '../input/index';
import {Dir, LayoutDirection} from '../core/rtl/dir';
import {FormControl, FormsModule, ReactiveFormsModule} from '@angular/forms';
import {Subscription} from 'rxjs/Subscription';
import {ENTER, DOWN_ARROW, SPACE, UP_ARROW, ESCAPE} from '../core/keyboard/keycodes';
import {MdOption} from '../core/option/option';
import {MdAutocomplete} from './autocomplete';
import {MdInputContainer} from '../input/input-container';
import {Observable} from 'rxjs/Observable';
import {Subject} from 'rxjs/Subject';
@@ -26,9 +30,9 @@ import {dispatchFakeEvent} from '../core/testing/dispatch-events';
import {createKeyboardEvent} from '../core/testing/event-objects';
import {typeInElement} from '../core/testing/type-in-element';
import {ScrollDispatcher} from '../core/overlay/scroll/scroll-dispatcher';
import 'rxjs/add/operator/map';
describe('MdAutocomplete', () => {
let overlayContainerElement: HTMLElement;
let dir: LayoutDirection;
@@ -50,7 +54,8 @@ describe('MdAutocomplete', () => {
NgIfAutocomplete,
AutocompleteWithNgModel,
AutocompleteWithOnPushDelay,
AutocompleteWithNativeInput
AutocompleteWithNativeInput,
AutocompleteWithoutPanel
],
providers: [
{provide: OverlayContainer, useFactory: () => {
@@ -1156,6 +1161,15 @@ describe('MdAutocomplete', () => {
expect(fixture.componentInstance.mdOptions.length).toBe(2);
}));
it('should throw if the user attempts to open the panel too early', async(() => {
const fixture = TestBed.createComponent(AutocompleteWithoutPanel);
fixture.detectChanges();
expect(() => {
fixture.componentInstance.trigger.openPanel();
}).toThrow(getMdAutocompleteMissingPanelError());
}));
});
it('should have correct width when opened', () => {
@@ -1422,3 +1436,11 @@ class AutocompleteWithNativeInput {
});
}
}
@Component({
template: `<input placeholder="Choose" [mdAutocomplete]="auto">`
})
class AutocompleteWithoutPanel {
@ViewChild(MdAutocompleteTrigger) trigger: MdAutocompleteTrigger;
}