Skip to content

Commit

Permalink
fix(autocomplete): error when clicking outside instance without mdInp…
Browse files Browse the repository at this point in the history
…ut (#4573)

Fixes an error that was being thrown if `md-autocomplete` is used on an input that's not a part of an `md-input-container`.

Fixes #4555.
  • Loading branch information
crisbeto authored and jelbourn committed May 17, 2017
1 parent 73d6814 commit e6f7ace
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 3 deletions.
8 changes: 6 additions & 2 deletions src/lib/autocomplete/autocomplete-trigger.ts
Expand Up @@ -186,9 +186,13 @@ export class MdAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
private get _outsideClickStream(): Observable<any> {
if (this._document) {
return Observable.fromEvent(this._document, 'click').filter((event: MouseEvent) => {
let clickTarget = event.target as HTMLElement;
const clickTarget = event.target as HTMLElement;
const inputContainer = this._inputContainer ?
this._inputContainer._elementRef.nativeElement : null;

return this._panelOpen &&
!this._inputContainer._elementRef.nativeElement.contains(clickTarget) &&
clickTarget !== this._element.nativeElement &&
(!inputContainer || !inputContainer.contains(clickTarget)) &&
!this._overlayRef.overlayElement.contains(clickTarget);
});
}
Expand Down
48 changes: 47 additions & 1 deletion src/lib/autocomplete/autocomplete.spec.ts
Expand Up @@ -48,7 +48,8 @@ describe('MdAutocomplete', () => {
AutocompleteWithoutForms,
NgIfAutocomplete,
AutocompleteWithNgModel,
AutocompleteWithOnPushDelay
AutocompleteWithOnPushDelay,
AutocompleteWithNativeInput
],
providers: [
{provide: OverlayContainer, useFactory: () => {
Expand Down Expand Up @@ -1065,6 +1066,24 @@ describe('MdAutocomplete', () => {
}));
});

describe('without mdInput', () => {
let fixture: ComponentFixture<AutocompleteWithNativeInput>;

beforeEach(() => {
fixture = TestBed.createComponent(AutocompleteWithNativeInput);
fixture.detectChanges();
});

it('should not throw when clicking outside', async(() => {
dispatchFakeEvent(fixture.debugElement.query(By.css('input')).nativeElement, 'focus');
fixture.detectChanges();

fixture.whenStable().then(() => {
expect(() => dispatchFakeEvent(document, 'click')).not.toThrow();
});
}));
});

describe('misc', () => {

it('should allow basic use without any forms directives', () => {
Expand Down Expand Up @@ -1373,6 +1392,33 @@ class AutocompleteWithOnPushDelay implements OnInit {
}
}

@Component({
template: `
<input placeholder="Choose" [mdAutocomplete]="auto" [formControl]="optionCtrl">
<md-autocomplete #auto="mdAutocomplete">
<md-option *ngFor="let option of filteredOptions | async" [value]="option">
{{option}}
</md-option>
</md-autocomplete>
`
})
class AutocompleteWithNativeInput {
optionCtrl = new FormControl();
filteredOptions: Observable<any>;
options = ['En', 'To', 'Tre', 'Fire', 'Fem'];

@ViewChild(MdAutocompleteTrigger) trigger: MdAutocompleteTrigger;
@ViewChildren(MdOption) mdOptions: QueryList<MdOption>;

constructor() {
this.filteredOptions = this.optionCtrl.valueChanges.startWith(null).map((val) => {
return val ? this.options.filter(option => new RegExp(val, 'gi').test(option))
: this.options.slice();
});
}
}


/** This is a mock keyboard event to test keyboard events in the autocomplete. */
class MockKeyboardEvent {
Expand Down

0 comments on commit e6f7ace

Please sign in to comment.