Skip to content

Commit cad0102

Browse files
crisbetojelbourn
authored andcommitted
fix(drag-drop): incorrectly constraining element position if size changes between drag sequences (#16876)
When a drag sequence is started we cache the dimensions of the element and the boundary so that we don't have to cause a reflow for each pixel of dragging, however with the current logic the cached dimensions are only cleared for the case where the item is part of a drop list. As a result, if a freely-dragged item with a boundary changes size between drag sequences its position won't be constrained correctly anymore. These changes fix the issue by correctly clearing the cached dimensions in all cases. Fixes #15749.
1 parent 99e66b8 commit cad0102

File tree

2 files changed

+26
-0
lines changed

2 files changed

+26
-0
lines changed

src/cdk/drag-drop/directives/drag.spec.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -763,6 +763,25 @@ describe('CdkDrag', () => {
763763
expect(dragElement.style.transform).toBe('translate3d(100px, 100px, 0px)');
764764
}));
765765

766+
it('should handle the element and boundary dimensions changing between drag sequences',
767+
fakeAsync(() => {
768+
const fixture = createComponent(StandaloneDraggable);
769+
const boundary: HTMLElement = fixture.nativeElement.querySelector('.wrapper');
770+
fixture.componentInstance.boundary = boundary;
771+
fixture.detectChanges();
772+
const dragElement = fixture.componentInstance.dragElement.nativeElement;
773+
774+
dragElementViaMouse(fixture, dragElement, 300, 300);
775+
expect(dragElement.style.transform).toBe('translate3d(100px, 100px, 0px)');
776+
777+
// Bump the width and height of both the boundary and the drag element.
778+
boundary.style.width = boundary.style.height = '300px';
779+
dragElement.style.width = dragElement.style.height = '150px';
780+
781+
dragElementViaMouse(fixture, dragElement, 300, 300);
782+
expect(dragElement.style.transform).toBe('translate3d(150px, 150px, 0px)');
783+
}));
784+
766785
it('should allow for the position constrain logic to be customized', fakeAsync(() => {
767786
const fixture = createComponent(StandaloneDraggable);
768787
const spy = jasmine.createSpy('constrain position spy').and.returnValue({

src/cdk/drag-drop/drag-ref.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -626,6 +626,7 @@ export class DragRef<T = any> {
626626
this._dropContainer._stopScrolling();
627627
this._animatePreviewToPlaceholder().then(() => {
628628
this._cleanupDragArtifacts(event);
629+
this._cleanupCachedDimensions();
629630
this._dragDropRegistry.stopDragging(this);
630631
});
631632
} else {
@@ -640,6 +641,7 @@ export class DragRef<T = any> {
640641
distance: this._getDragDistance(this._getPointerPositionOnPage(event))
641642
});
642643
});
644+
this._cleanupCachedDimensions();
643645
this._dragDropRegistry.stopDragging(this);
644646
}
645647
}
@@ -1079,6 +1081,11 @@ export class DragRef<T = any> {
10791081

10801082
return {x: 0, y: 0};
10811083
}
1084+
1085+
/** Cleans up any cached element dimensions that we don't need after dragging has stopped. */
1086+
private _cleanupCachedDimensions() {
1087+
this._boundaryRect = this._previewRect = undefined;
1088+
}
10821089
}
10831090

10841091
/** Point on the page or within an element. */

0 commit comments

Comments
 (0)