From 1783d7369a71f1835c76242361686bd16bf0289d Mon Sep 17 00:00:00 2001 From: crisbeto Date: Mon, 15 May 2017 22:35:39 +0200 Subject: [PATCH 1/2] fix(autocomplete): error when clicking outside instance without mdInput 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. --- src/lib/autocomplete/autocomplete-trigger.ts | 8 +++- src/lib/autocomplete/autocomplete.spec.ts | 48 +++++++++++++++++++- 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/src/lib/autocomplete/autocomplete-trigger.ts b/src/lib/autocomplete/autocomplete-trigger.ts index 4ecefc833b50..c942146da052 100644 --- a/src/lib/autocomplete/autocomplete-trigger.ts +++ b/src/lib/autocomplete/autocomplete-trigger.ts @@ -186,9 +186,13 @@ export class MdAutocompleteTrigger implements ControlValueAccessor, OnDestroy { private get _outsideClickStream(): Observable { 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); }); } diff --git a/src/lib/autocomplete/autocomplete.spec.ts b/src/lib/autocomplete/autocomplete.spec.ts index 7336516b6c55..52d470a0aaea 100644 --- a/src/lib/autocomplete/autocomplete.spec.ts +++ b/src/lib/autocomplete/autocomplete.spec.ts @@ -48,7 +48,8 @@ describe('MdAutocomplete', () => { AutocompleteWithoutForms, NgIfAutocomplete, AutocompleteWithNgModel, - AutocompleteWithOnPushDelay + AutocompleteWithOnPushDelay, + AutocompleteWithNativeInput ], providers: [ {provide: OverlayContainer, useFactory: () => { @@ -1065,6 +1066,24 @@ describe('MdAutocomplete', () => { })); }); + describe('without mdInput', () => { + let fixture: ComponentFixture; + + 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', () => { @@ -1373,6 +1392,33 @@ class AutocompleteWithOnPushDelay implements OnInit { } } +@Component({ + template: ` + + + + + {{option}} + + + ` +}) +class AutocompleteWithNativeInput { + optionCtrl = new FormControl(); + filteredOptions: Observable; + options = ['En', 'To', 'Tre', 'Fire', 'Fem']; + + @ViewChild(MdAutocompleteTrigger) trigger: MdAutocompleteTrigger; + @ViewChildren(MdOption) mdOptions: QueryList; + + 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 { From ae405540404cc2208aae83072d4fbb979167a3ad Mon Sep 17 00:00:00 2001 From: crisbeto Date: Mon, 15 May 2017 23:40:35 +0200 Subject: [PATCH 2/2] chore: remove mdInput --- src/lib/autocomplete/autocomplete.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/autocomplete/autocomplete.spec.ts b/src/lib/autocomplete/autocomplete.spec.ts index 52d470a0aaea..93b7b13aa40b 100644 --- a/src/lib/autocomplete/autocomplete.spec.ts +++ b/src/lib/autocomplete/autocomplete.spec.ts @@ -1394,7 +1394,7 @@ class AutocompleteWithOnPushDelay implements OnInit { @Component({ template: ` - +