Skip to content

Commit 749d3ba

Browse files
committed
fix(material/autocomplete): not closing when clicking outside while propagation is stopped
Fixes the autocomplete panel not closing if the user clicks outside on an element that stops propagation of the `click` event (e.g. a `mat-chip`). Fixes #17352.
1 parent 6b2b518 commit 749d3ba

File tree

3 files changed

+37
-3
lines changed

3 files changed

+37
-3
lines changed

src/material-experimental/mdc-autocomplete/autocomplete.spec.ts

+16
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,20 @@ describe('MDC-based MatAutocomplete', () => {
208208
.toEqual('');
209209
}));
210210

211+
it('should close the panel when clicking away and propagation is stopped', fakeAsync(() => {
212+
const trigger = fixture.componentInstance.trigger;
213+
dispatchFakeEvent(input, 'focusin');
214+
fixture.detectChanges();
215+
zone.simulateZoneExit();
216+
217+
expect(trigger.panelOpen).toBe(true, 'Expected panel to be open.');
218+
219+
fixture.nativeElement.querySelector('.stop-propagation').click();
220+
fixture.detectChanges();
221+
222+
expect(trigger.panelOpen).toBe(false, 'Expected panel to be closed.');
223+
}));
224+
211225
it('should close the panel when the user taps away on a touch device', fakeAsync(() => {
212226
dispatchFakeEvent(input, 'focus');
213227
fixture.detectChanges();
@@ -3374,6 +3388,8 @@ const SIMPLE_AUTOCOMPLETE_TEMPLATE = `
33743388
<span>{{ state.code }}: {{ state.name }}</span>
33753389
</mat-option>
33763390
</mat-autocomplete>
3391+
3392+
<button class="stop-propagation" (click)="$event.stopPropagation()">Click me</button>
33773393
`;
33783394

33793395
@Component({template: SIMPLE_AUTOCOMPLETE_TEMPLATE})

src/material/autocomplete/autocomplete-trigger.ts

+5-3
Original file line numberDiff line numberDiff line change
@@ -349,10 +349,12 @@ export abstract class _MatAutocompleteTriggerBase
349349

350350
/** Stream of clicks outside of the autocomplete panel. */
351351
private _getOutsideClickStream(): Observable<any> {
352+
// Use capturing so we can close even if propagation is stopped.
353+
const eventOptions = {capture: true};
352354
return merge(
353-
fromEvent(this._document, 'click') as Observable<MouseEvent>,
354-
fromEvent(this._document, 'auxclick') as Observable<MouseEvent>,
355-
fromEvent(this._document, 'touchend') as Observable<TouchEvent>,
355+
fromEvent(this._document, 'click', eventOptions) as Observable<MouseEvent>,
356+
fromEvent(this._document, 'auxclick', eventOptions) as Observable<MouseEvent>,
357+
fromEvent(this._document, 'touchend', eventOptions) as Observable<TouchEvent>,
356358
).pipe(
357359
filter(event => {
358360
// If we're in the Shadow DOM, the event target will be the shadow root, so we have to

src/material/autocomplete/autocomplete.spec.ts

+16
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,20 @@ describe('MatAutocomplete', () => {
210210
.toEqual('');
211211
}));
212212

213+
it('should close the panel when clicking away and propagation is stopped', fakeAsync(() => {
214+
const trigger = fixture.componentInstance.trigger;
215+
dispatchFakeEvent(input, 'focusin');
216+
fixture.detectChanges();
217+
zone.simulateZoneExit();
218+
219+
expect(trigger.panelOpen).toBe(true, 'Expected panel to be open.');
220+
221+
fixture.nativeElement.querySelector('.stop-propagation').click();
222+
fixture.detectChanges();
223+
224+
expect(trigger.panelOpen).toBe(false, 'Expected panel to be closed.');
225+
}));
226+
213227
it('should close the panel when the user taps away on a touch device', fakeAsync(() => {
214228
dispatchFakeEvent(input, 'focus');
215229
fixture.detectChanges();
@@ -3379,6 +3393,8 @@ const SIMPLE_AUTOCOMPLETE_TEMPLATE = `
33793393
<span>{{ state.code }}: {{ state.name }}</span>
33803394
</mat-option>
33813395
</mat-autocomplete>
3396+
3397+
<button class="stop-propagation" (click)="$event.stopPropagation()">Click me</button>
33823398
`;
33833399

33843400
@Component({template: SIMPLE_AUTOCOMPLETE_TEMPLATE})

0 commit comments

Comments
 (0)