AAE-50593 Fix: memory leaks in datatable column-resize directives (#12180)

* fix: memory leaks in datatable column-resize directives

Co-authored-by: eromano <1030050+eromano@users.noreply.github.com>

* test: add regression test for mouseup listener cleanup on repeated mousedown

Co-authored-by: eromano <1030050+eromano@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: eromano <1030050+eromano@users.noreply.github.com>
This commit is contained in:
Copilot
2026-08-19 10:23:43 +02:00
committed by GitHub
co-authored by eromano
parent f907f8ef10
commit 70db1e383f
3 changed files with 29 additions and 2 deletions
@@ -131,7 +131,10 @@ export class ResizableDirective implements OnInit, OnDestroy {
.pipe(filter(() => !!this.currentRect));
mouseDrag
.pipe(map(({ clientX }) => this.getNewBoundingRectangle(this.startingRect, clientX + this.coverPadding)))
.pipe(
map(({ clientX }) => this.getNewBoundingRectangle(this.startingRect, clientX + this.coverPadding)),
takeUntilDestroyed(this.destroyRef)
)
.subscribe((rectangle: BoundingRectangle) => {
if (this.resizing.observers.length > 0) {
this.zone.run(() => {
@@ -131,6 +131,28 @@ describe('ResizeHandleDirective', () => {
expect(renderer.listen).toHaveBeenCalledWith(element.nativeElement, 'mousemove', jasmine.any(Function));
expect(renderer.listen).toHaveBeenCalledWith('document', 'mouseup', jasmine.any(Function));
});
it('should unregister previous mouseup listener before registering a new one on repeated mousedown', () => {
const firstUnlistenMouseUp = jasmine.createSpy('firstUnlistenMouseUp');
const secondUnlistenMouseUp = jasmine.createSpy('secondUnlistenMouseUp');
let mouseUpCallCount = 0;
renderer.listen.and.callFake((_target: any, eventName: string, _callback: (event: MouseEvent) => void) => {
if (eventName === 'mouseup') {
mouseUpCallCount++;
return mouseUpCallCount === 1 ? firstUnlistenMouseUp : secondUnlistenMouseUp;
}
return () => {};
});
const mouseEvent = new MouseEvent('mousedown', { cancelable: true });
mousedownCallback(mouseEvent);
expect(firstUnlistenMouseUp).not.toHaveBeenCalled();
mousedownCallback(mouseEvent);
expect(firstUnlistenMouseUp).toHaveBeenCalled();
});
});
describe('keyboard resizing', () => {
@@ -86,6 +86,7 @@ export class ResizeHandleDirective implements OnInit, OnDestroy {
});
}
this.unlistenMouseUp?.();
this.unlistenMouseUp = this.renderer.listen('document', 'mouseup', (mouseUpEvent: MouseEvent) => {
this.onMouseup(mouseUpEvent);
});
@@ -96,7 +97,8 @@ export class ResizeHandleDirective implements OnInit, OnDestroy {
private onMouseup(event: MouseEvent): void {
this.unlistenMouseMove?.();
this.unlistenMouseMove = undefined;
this.unlistenMouseUp();
this.unlistenMouseUp?.();
this.unlistenMouseUp = undefined;
this.resizableContainer.mouseup.next(event);
}