Skip to content

Commit e97d6ee

Browse files
committed
fix(drag-drop): unable to start dragging in list if dragged item is destroyed
We currently have some logic which cleans up the dragging state if the dragged item is destroyed, but nothing notifies the parent drop list which leaves it in the dragging state. Next time the user tries to drag, they won't be able to, because the list still thinks that its dragging. These changes add some logic to abort the dragging if the dragged item is removed from the list. Fixes #18628.
1 parent 695dde6 commit e97d6ee

File tree

2 files changed

+49
-2
lines changed

2 files changed

+49
-2
lines changed

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

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3801,6 +3801,38 @@ describe('CdkDrag', () => {
38013801
expect(styles.scrollSnapType || styles.msScrollSnapType).toBe('block');
38023802
}));
38033803

3804+
it('should dispatch the `dropped` event when an item has been dropped', fakeAsync(() => {
3805+
const fixture = createComponent(DraggableInDropZone);
3806+
fixture.detectChanges();
3807+
3808+
let item = fixture.componentInstance.dragItems.first;
3809+
startDraggingViaMouse(fixture, item.element.nativeElement);
3810+
expect(document.querySelector('.cdk-drop-list-dragging'))
3811+
.toBeTruthy('Expected to drag initially.');
3812+
3813+
fixture.componentInstance.items = [
3814+
{value: 'Five', height: ITEM_HEIGHT, margin: 0},
3815+
{value: 'Six', height: ITEM_HEIGHT, margin: 0}
3816+
];
3817+
fixture.detectChanges();
3818+
3819+
expect(fixture.componentInstance.droppedSpy).not.toHaveBeenCalled();
3820+
expect(document.querySelector('.cdk-drop-list-dragging'))
3821+
.toBeFalsy('Expected not to be dragging after item is destroyed.');
3822+
3823+
item = fixture.componentInstance.dragItems.first;
3824+
startDraggingViaMouse(fixture, item.element.nativeElement);
3825+
3826+
expect(document.querySelector('.cdk-drop-list-dragging'))
3827+
.toBeTruthy('Expected to be able to start a new drag sequence.');
3828+
3829+
dispatchMouseEvent(document, 'mouseup');
3830+
fixture.detectChanges();
3831+
flush();
3832+
3833+
expect(fixture.componentInstance.droppedSpy).toHaveBeenCalledTimes(1);
3834+
}));
3835+
38043836
});
38053837

38063838
describe('in a connected drop container', () => {

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

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -367,11 +367,20 @@ export class DropListRef<T = any> {
367367
* @param items Items that are a part of this list.
368368
*/
369369
withItems(items: DragRef[]): this {
370+
const previousItems = this._draggables;
370371
this._draggables = items;
371372
items.forEach(item => item._withDropContainer(this));
372373

373374
if (this.isDragging()) {
374-
this._cacheItems();
375+
const draggedItems = previousItems.filter(item => item.isDragging());
376+
377+
// If all of the items being dragged were removed
378+
// from the list, abort the current drag sequence.
379+
if (draggedItems.every(item => items.indexOf(item) === -1)) {
380+
this._reset();
381+
} else {
382+
this._cacheItems();
383+
}
375384
}
376385

377386
return this;
@@ -631,7 +640,13 @@ export class DropListRef<T = any> {
631640
(styles as any).scrollSnapType = styles.msScrollSnapType = this._initialScrollSnap;
632641

633642
// TODO(crisbeto): may have to wait for the animations to finish.
634-
this._activeDraggables.forEach(item => item.getRootElement().style.transform = '');
643+
this._activeDraggables.forEach(item => {
644+
const rootElement = item.getRootElement();
645+
646+
if (rootElement) {
647+
rootElement.style.transform = '';
648+
}
649+
});
635650
this._siblings.forEach(sibling => sibling._stopReceiving(this));
636651
this._activeDraggables = [];
637652
this._itemPositions = [];

0 commit comments

Comments
 (0)