Skip to content

Commit 4679592

Browse files
authored
perf(module:dropdown): do not run change detection if the dropdown has been clicked inside (#7135)
1 parent fc991d1 commit 4679592

File tree

2 files changed

+37
-14
lines changed

2 files changed

+37
-14
lines changed

components/dropdown/context-menu.service.spec.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { OverlayContainer, ScrollDispatcher } from '@angular/cdk/overlay';
2-
import { Component, Provider, Type, ViewChild } from '@angular/core';
2+
import { ApplicationRef, Component, Provider, Type, ViewChild } from '@angular/core';
33
import { ComponentFixture, fakeAsync, inject, TestBed, tick } from '@angular/core/testing';
44
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
55
import { Subject } from 'rxjs';
@@ -119,6 +119,22 @@ describe('context-menu', () => {
119119
expect(overlayContainerElement.textContent).toBe('');
120120
}).not.toThrowError();
121121
}));
122+
it('should not run change detection if the overlay is clicked inside', async () => {
123+
const fixture = createComponent(NzTestDropdownContextMenuComponent, [], []);
124+
fixture.detectChanges();
125+
const fakeEvent = createMouseEvent('contextmenu', 300, 300);
126+
const component = fixture.componentInstance;
127+
component.nzContextMenuService.create(fakeEvent, component.nzDropdownMenuComponent);
128+
fixture.detectChanges();
129+
await fixture.whenStable();
130+
fixture.detectChanges();
131+
const appRef = TestBed.inject(ApplicationRef);
132+
spyOn(appRef, 'tick');
133+
overlayContainerElement.querySelector('ul')!.click();
134+
expect(appRef.tick).toHaveBeenCalledTimes(0);
135+
document.body.click();
136+
expect(appRef.tick).toHaveBeenCalledTimes(1);
137+
});
122138
});
123139

124140
@Component({

components/dropdown/context-menu.service.ts

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55

66
import { ConnectionPositionPair, Overlay, OverlayRef } from '@angular/cdk/overlay';
77
import { TemplatePortal } from '@angular/cdk/portal';
8-
import { Injectable } from '@angular/core';
9-
import { fromEvent, merge, Subscription } from 'rxjs';
8+
import { Injectable, NgZone } from '@angular/core';
9+
import { fromEvent, Subscription } from 'rxjs';
1010
import { filter, take } from 'rxjs/operators';
1111

1212
import { NzContextMenuServiceModule } from './context-menu.service.module';
@@ -26,7 +26,7 @@ export class NzContextMenuService {
2626
private overlayRef: OverlayRef | null = null;
2727
private closeSubscription = Subscription.EMPTY;
2828

29-
constructor(private overlay: Overlay) {}
29+
constructor(private ngZone: NgZone, private overlay: Overlay) {}
3030

3131
create($event: MouseEvent | { x: number; y: number }, nzDropdownMenuComponent: NzDropdownMenuComponent): void {
3232
this.close(true);
@@ -44,17 +44,24 @@ export class NzContextMenuService {
4444
disposeOnNavigation: true,
4545
scrollStrategy: this.overlay.scrollStrategies.close()
4646
});
47-
this.closeSubscription = merge(
48-
nzDropdownMenuComponent.descendantMenuItemClick$,
49-
fromEvent<MouseEvent>(document, 'click').pipe(
50-
filter(event => !!this.overlayRef && !this.overlayRef.overlayElement.contains(event.target as HTMLElement)),
51-
/** handle firefox contextmenu event **/
52-
filter(event => event.button !== 2),
53-
take(1)
47+
48+
this.closeSubscription = new Subscription();
49+
50+
this.closeSubscription.add(nzDropdownMenuComponent.descendantMenuItemClick$.subscribe(() => this.close()));
51+
52+
this.closeSubscription.add(
53+
this.ngZone.runOutsideAngular(() =>
54+
fromEvent<MouseEvent>(document, 'click')
55+
.pipe(
56+
filter(event => !!this.overlayRef && !this.overlayRef.overlayElement.contains(event.target as HTMLElement)),
57+
/** handle firefox contextmenu event **/
58+
filter(event => event.button !== 2),
59+
take(1)
60+
)
61+
.subscribe(() => this.ngZone.run(() => this.close()))
5462
)
55-
).subscribe(() => {
56-
this.close();
57-
});
63+
);
64+
5865
this.overlayRef.attach(
5966
new TemplatePortal(nzDropdownMenuComponent.templateRef, nzDropdownMenuComponent.viewContainerRef)
6067
);

0 commit comments

Comments
 (0)