From 286d126a6d7429f14f4b8ae048fbf433b08d1243 Mon Sep 17 00:00:00 2001 From: crisbeto Date: Wed, 12 Sep 2018 21:35:49 +0200 Subject: [PATCH] fix(drag-drop): not dropping immediately for failed drag after a successful one Fixes the `CdkDrag` having to fall back to waiting for the animation to time out, rather than exiting immediately if the user does a successful dragging sequence, followed by an unsuccessful one. The issue comes from the fact that the `_hasMoved` flag was never being reset. Fixes #13091. --- src/cdk/drag-drop/drag.spec.ts | 33 +++++++++++++++++++++++++++++++++ src/cdk/drag-drop/drag.ts | 3 ++- 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/src/cdk/drag-drop/drag.spec.ts b/src/cdk/drag-drop/drag.spec.ts index 4e991b0541df..05a1b811b922 100644 --- a/src/cdk/drag-drop/drag.spec.ts +++ b/src/cdk/drag-drop/drag.spec.ts @@ -683,6 +683,39 @@ describe('CdkDrag', () => { .toBeFalsy('Expected preview to be removed from the DOM if the transition timed out'); })); + it('should reset immediately when failed drag happens after a successful one', fakeAsync(() => { + const fixture = createComponent(DraggableInDropZone); + fixture.detectChanges(); + + const itemInstance = fixture.componentInstance.dragItems.toArray()[1]; + const item = itemInstance.element.nativeElement; + const spy = jasmine.createSpy('dropped spy'); + const subscription = itemInstance.dropped.asObservable().subscribe(spy); + + // Do an initial drag and drop sequence. + dragElementViaMouse(fixture, item, 50, 50); + tick(0); // Important to tick with 0 since we don't want to flush any pending timeouts. + + expect(spy).toHaveBeenCalledTimes(1); + + // Start another drag. + dispatchMouseEvent(item, 'mousedown'); + fixture.detectChanges(); + + // Add a duration since the tests won't include one. + const preview = document.querySelector('.cdk-drag-preview')! as HTMLElement; + preview.style.transitionDuration = '500ms'; + + // Dispatch the mouseup immediately to simulate the user not moving the element. + dispatchMouseEvent(document, 'mouseup'); + fixture.detectChanges(); + tick(0); // Important to tick with 0 since we don't want to flush any pending timeouts. + + expect(spy).toHaveBeenCalledTimes(2); + + subscription.unsubscribe(); + })); + it('should not wait for transition that are not on the `transform` property', fakeAsync(() => { const fixture = createComponent(DraggableInDropZone); fixture.detectChanges(); diff --git a/src/cdk/drag-drop/drag.ts b/src/cdk/drag-drop/drag.ts index 44484b5e1a49..dce7f6e5ddc8 100644 --- a/src/cdk/drag-drop/drag.ts +++ b/src/cdk/drag-drop/drag.ts @@ -103,7 +103,7 @@ export class CdkDrag implements AfterViewInit, OnDestroy { private _activeTransform: Point = {x: 0, y: 0}; /** Whether the element has moved since the user started dragging it. */ - private _hasMoved = false; + private _hasMoved: boolean; /** Drop container in which the CdkDrag resided when dragging began. */ private _initialContainer: CdkDropContainer; @@ -284,6 +284,7 @@ export class CdkDrag implements AfterViewInit, OnDestroy { const endedOrDestroyed = merge(this.ended, this._destroyed); + this._hasMoved = false; this._dragDropRegistry.pointerMove .pipe(takeUntil(endedOrDestroyed)) .subscribe(this._pointerMove);