Skip to content

Commit e6f7ace

Browse files
crisbetojelbourn
authored andcommitted
fix(autocomplete): error when clicking outside instance without mdInput (#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.
1 parent 73d6814 commit e6f7ace

File tree

2 files changed

+53
-3
lines changed

2 files changed

+53
-3
lines changed

src/lib/autocomplete/autocomplete-trigger.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -186,9 +186,13 @@ export class MdAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
186186
private get _outsideClickStream(): Observable<any> {
187187
if (this._document) {
188188
return Observable.fromEvent(this._document, 'click').filter((event: MouseEvent) => {
189-
let clickTarget = event.target as HTMLElement;
189+
const clickTarget = event.target as HTMLElement;
190+
const inputContainer = this._inputContainer ?
191+
this._inputContainer._elementRef.nativeElement : null;
192+
190193
return this._panelOpen &&
191-
!this._inputContainer._elementRef.nativeElement.contains(clickTarget) &&
194+
clickTarget !== this._element.nativeElement &&
195+
(!inputContainer || !inputContainer.contains(clickTarget)) &&
192196
!this._overlayRef.overlayElement.contains(clickTarget);
193197
});
194198
}

src/lib/autocomplete/autocomplete.spec.ts

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@ describe('MdAutocomplete', () => {
4848
AutocompleteWithoutForms,
4949
NgIfAutocomplete,
5050
AutocompleteWithNgModel,
51-
AutocompleteWithOnPushDelay
51+
AutocompleteWithOnPushDelay,
52+
AutocompleteWithNativeInput
5253
],
5354
providers: [
5455
{provide: OverlayContainer, useFactory: () => {
@@ -1065,6 +1066,24 @@ describe('MdAutocomplete', () => {
10651066
}));
10661067
});
10671068

1069+
describe('without mdInput', () => {
1070+
let fixture: ComponentFixture<AutocompleteWithNativeInput>;
1071+
1072+
beforeEach(() => {
1073+
fixture = TestBed.createComponent(AutocompleteWithNativeInput);
1074+
fixture.detectChanges();
1075+
});
1076+
1077+
it('should not throw when clicking outside', async(() => {
1078+
dispatchFakeEvent(fixture.debugElement.query(By.css('input')).nativeElement, 'focus');
1079+
fixture.detectChanges();
1080+
1081+
fixture.whenStable().then(() => {
1082+
expect(() => dispatchFakeEvent(document, 'click')).not.toThrow();
1083+
});
1084+
}));
1085+
});
1086+
10681087
describe('misc', () => {
10691088

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

1395+
@Component({
1396+
template: `
1397+
<input placeholder="Choose" [mdAutocomplete]="auto" [formControl]="optionCtrl">
1398+
1399+
<md-autocomplete #auto="mdAutocomplete">
1400+
<md-option *ngFor="let option of filteredOptions | async" [value]="option">
1401+
{{option}}
1402+
</md-option>
1403+
</md-autocomplete>
1404+
`
1405+
})
1406+
class AutocompleteWithNativeInput {
1407+
optionCtrl = new FormControl();
1408+
filteredOptions: Observable<any>;
1409+
options = ['En', 'To', 'Tre', 'Fire', 'Fem'];
1410+
1411+
@ViewChild(MdAutocompleteTrigger) trigger: MdAutocompleteTrigger;
1412+
@ViewChildren(MdOption) mdOptions: QueryList<MdOption>;
1413+
1414+
constructor() {
1415+
this.filteredOptions = this.optionCtrl.valueChanges.startWith(null).map((val) => {
1416+
return val ? this.options.filter(option => new RegExp(val, 'gi').test(option))
1417+
: this.options.slice();
1418+
});
1419+
}
1420+
}
1421+
13761422

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

0 commit comments

Comments
 (0)