From 0431d8152bb1a0ff2c4bec31bb8684a8cba04b5f Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Thu, 10 Jun 2021 14:43:37 +0200 Subject: [PATCH] fix(cdk/drag-drop): error if dragged item is destroyed as a result of the `entered` event (#22904) When an item enters a new drop container, we dispatch an event and run some logic afterwards. The problem is that if the item is destroyed as a result of the event, the logic after the event will throw because dragging was interrupted. Fixes #22813. --- src/cdk/drag-drop/directives/drag.spec.ts | 22 ++++++++++++++++++++++ src/cdk/drag-drop/drag-ref.ts | 13 ++++++++----- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/src/cdk/drag-drop/directives/drag.spec.ts b/src/cdk/drag-drop/directives/drag.spec.ts index 03f50c5ac225..4986bc7e4636 100644 --- a/src/cdk/drag-drop/directives/drag.spec.ts +++ b/src/cdk/drag-drop/directives/drag.spec.ts @@ -5447,6 +5447,28 @@ describe('CdkDrag', () => { expect(itemEnterEvent).toEqual(expectedEvent); })); + it('should not throw if dragging was interrupted as a result of the entered event', + fakeAsync(() => { + const fixture = createComponent(ConnectedDropZones); + fixture.detectChanges(); + + const groups = fixture.componentInstance.groupedDragItems; + const item = groups[0][1]; + const targetRect = groups[1][2].element.nativeElement.getBoundingClientRect(); + + fixture.componentInstance.enteredSpy.and.callFake(() => { + fixture.componentInstance.todo = []; + fixture.detectChanges(); + }); + + expect(() => { + dragElementViaMouse( + fixture, item.element.nativeElement, targetRect.left + 1, targetRect.top + 1); + flush(); + fixture.detectChanges(); + }).not.toThrow(); + })); + it('should be able to drop into a new container after scrolling into view', fakeAsync(() => { const fixture = createComponent(ConnectedDropZones); fixture.detectChanges(); diff --git a/src/cdk/drag-drop/drag-ref.ts b/src/cdk/drag-drop/drag-ref.ts index 72e9c057f516..6c66c0df21e6 100644 --- a/src/cdk/drag-drop/drag-ref.ts +++ b/src/cdk/drag-drop/drag-ref.ts @@ -151,7 +151,7 @@ export class DragRef { * Whether the dragging sequence has been started. Doesn't * necessarily mean that the element has been moved. */ - private _hasStartedDragging: boolean; + private _hasStartedDragging = false; /** Whether the element has moved since the user started dragging it. */ private _hasMoved: boolean; @@ -982,10 +982,13 @@ export class DragRef { }); } - this._dropContainer!._startScrollingIfNecessary(rawX, rawY); - this._dropContainer!._sortItem(this, x, y, this._pointerDirectionDelta); - this._applyPreviewTransform( - x - this._pickupPositionInElement.x, y - this._pickupPositionInElement.y); + // Dragging may have been interrupted as a result of the events above. + if (this.isDragging()) { + this._dropContainer!._startScrollingIfNecessary(rawX, rawY); + this._dropContainer!._sortItem(this, x, y, this._pointerDirectionDelta); + this._applyPreviewTransform( + x - this._pickupPositionInElement.x, y - this._pickupPositionInElement.y); + } } /**