Skip to content

Commit

Permalink
fix(material/autocomplete): outside click in Angular zone.
Browse files Browse the repository at this point in the history
Fixes a bug in Angular Material `autocomplete` when outside click doesn't trigger `changeDetection`.

Fixes #24811
  • Loading branch information
volvachev authored and Egor Volvachev committed Apr 22, 2022
1 parent c6a1d15 commit db3bf3d
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 1 deletion.
26 changes: 26 additions & 0 deletions src/material-experimental/mdc-autocomplete/autocomplete.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3365,6 +3365,32 @@ describe('MDC-based MatAutocomplete', () => {

expect(fixture.componentInstance.trigger.panelOpen).toBe(true);
});

it('should emit from `autocomplete.closed` after click outside inside the NgZone', fakeAsync(() => {
const inZoneSpy = jasmine.createSpy('in zone spy');

const fixture = createComponent(SimpleAutocomplete, [
{provide: NgZone, useFactory: () => new NgZone({enableLongStackTrace: false})},
]);
const zone = TestBed.inject(NgZone);
fixture.detectChanges();

fixture.componentInstance.trigger.openPanel();
fixture.detectChanges();
flush();

const subscription = fixture.componentInstance.trigger.autocomplete.closed.subscribe(() =>
inZoneSpy(NgZone.isInAngularZone()),
);
zone.onStable.emit(null);

dispatchFakeEvent(document, 'click');

expect(inZoneSpy).toHaveBeenCalled();
expect(inZoneSpy).toHaveBeenCalledWith(true);

subscription.unsubscribe();
}));
});

const SIMPLE_AUTOCOMPLETE_TEMPLATE = `
Expand Down
7 changes: 6 additions & 1 deletion src/material/autocomplete/autocomplete-trigger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,12 @@ export abstract class _MatAutocompleteTriggerBase

if (this.panelOpen) {
// Only emit if the panel was visible.
this.autocomplete.closed.emit();
// The `NgZone.onStable` always emits outside of the Angular zone,
// so all the subscriptions from `_subscribeToClosingActions()` are also outside of the Angular zone.
// We should manually run in Angular zone to update UI after panel closing.
this._zone.run(() => {
this.autocomplete.closed.emit();
});
}

this.autocomplete._isOpen = this._overlayAttached = false;
Expand Down
26 changes: 26 additions & 0 deletions src/material/autocomplete/autocomplete.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3371,6 +3371,32 @@ describe('MatAutocomplete', () => {

expect(fixture.componentInstance.trigger.panelOpen).toBe(true);
});

it('should emit from `autocomplete.closed` after click outside inside the NgZone', fakeAsync(() => {
const inZoneSpy = jasmine.createSpy('in zone spy');

const fixture = createComponent(SimpleAutocomplete, [
{provide: NgZone, useFactory: () => new NgZone({enableLongStackTrace: false})},
]);
const zone = TestBed.inject(NgZone);
fixture.detectChanges();

fixture.componentInstance.trigger.openPanel();
fixture.detectChanges();
flush();

const subscription = fixture.componentInstance.trigger.autocomplete.closed.subscribe(() =>
inZoneSpy(NgZone.isInAngularZone()),
);
zone.onStable.emit(null);

dispatchFakeEvent(document, 'click');

expect(inZoneSpy).toHaveBeenCalled();
expect(inZoneSpy).toHaveBeenCalledWith(true);

subscription.unsubscribe();
}));
});

const SIMPLE_AUTOCOMPLETE_TEMPLATE = `
Expand Down

0 comments on commit db3bf3d

Please sign in to comment.