diff --git a/src/material-experimental/mdc-autocomplete/autocomplete.spec.ts b/src/material-experimental/mdc-autocomplete/autocomplete.spec.ts index 621e2d69855e..7e89caf5b08b 100644 --- a/src/material-experimental/mdc-autocomplete/autocomplete.spec.ts +++ b/src/material-experimental/mdc-autocomplete/autocomplete.spec.ts @@ -208,6 +208,20 @@ describe('MDC-based MatAutocomplete', () => { .toEqual(''); })); + it('should close the panel when clicking away and propagation is stopped', fakeAsync(() => { + const trigger = fixture.componentInstance.trigger; + dispatchFakeEvent(input, 'focusin'); + fixture.detectChanges(); + zone.simulateZoneExit(); + + expect(trigger.panelOpen).toBe(true, 'Expected panel to be open.'); + + fixture.nativeElement.querySelector('.stop-propagation').click(); + fixture.detectChanges(); + + expect(trigger.panelOpen).toBe(false, 'Expected panel to be closed.'); + })); + it('should close the panel when the user taps away on a touch device', fakeAsync(() => { dispatchFakeEvent(input, 'focus'); fixture.detectChanges(); @@ -3374,6 +3388,8 @@ const SIMPLE_AUTOCOMPLETE_TEMPLATE = ` {{ state.code }}: {{ state.name }} + + `; @Component({template: SIMPLE_AUTOCOMPLETE_TEMPLATE}) diff --git a/src/material/autocomplete/autocomplete-trigger.ts b/src/material/autocomplete/autocomplete-trigger.ts index 50a205af693f..c55692934058 100644 --- a/src/material/autocomplete/autocomplete-trigger.ts +++ b/src/material/autocomplete/autocomplete-trigger.ts @@ -349,10 +349,12 @@ export abstract class _MatAutocompleteTriggerBase /** Stream of clicks outside of the autocomplete panel. */ private _getOutsideClickStream(): Observable { + // Use capturing so we can close even if propagation is stopped. + const eventOptions = {capture: true}; return merge( - fromEvent(this._document, 'click') as Observable, - fromEvent(this._document, 'auxclick') as Observable, - fromEvent(this._document, 'touchend') as Observable, + fromEvent(this._document, 'click', eventOptions) as Observable, + fromEvent(this._document, 'auxclick', eventOptions) as Observable, + fromEvent(this._document, 'touchend', eventOptions) as Observable, ).pipe( filter(event => { // If we're in the Shadow DOM, the event target will be the shadow root, so we have to diff --git a/src/material/autocomplete/autocomplete.spec.ts b/src/material/autocomplete/autocomplete.spec.ts index ed41c3acbceb..5b08d705e4d6 100644 --- a/src/material/autocomplete/autocomplete.spec.ts +++ b/src/material/autocomplete/autocomplete.spec.ts @@ -210,6 +210,20 @@ describe('MatAutocomplete', () => { .toEqual(''); })); + it('should close the panel when clicking away and propagation is stopped', fakeAsync(() => { + const trigger = fixture.componentInstance.trigger; + dispatchFakeEvent(input, 'focusin'); + fixture.detectChanges(); + zone.simulateZoneExit(); + + expect(trigger.panelOpen).toBe(true, 'Expected panel to be open.'); + + fixture.nativeElement.querySelector('.stop-propagation').click(); + fixture.detectChanges(); + + expect(trigger.panelOpen).toBe(false, 'Expected panel to be closed.'); + })); + it('should close the panel when the user taps away on a touch device', fakeAsync(() => { dispatchFakeEvent(input, 'focus'); fixture.detectChanges(); @@ -3379,6 +3393,8 @@ const SIMPLE_AUTOCOMPLETE_TEMPLATE = ` {{ state.code }}: {{ state.name }} + + `; @Component({template: SIMPLE_AUTOCOMPLETE_TEMPLATE})