Skip to content

Commit fa83805

Browse files
crisbetojosephperrott
authored andcommitted
fix(drag-drop): unable to drag last item back into initial container (#12261)
1 parent 0291ec4 commit fa83805

File tree

3 files changed

+68
-15
lines changed

3 files changed

+68
-15
lines changed

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

Lines changed: 60 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -657,7 +657,8 @@ describe('CdkDrag', () => {
657657
const initialRect = item.element.nativeElement.getBoundingClientRect();
658658
const targetRect = groups[1][2].element.nativeElement.getBoundingClientRect();
659659

660-
expect(dropZones[0].contains(item.element.nativeElement)).toBe(true);
660+
expect(dropZones[0].contains(item.element.nativeElement))
661+
.toBe(true, 'Expected placeholder to be inside the first container.');
661662
dispatchMouseEvent(item.element.nativeElement, 'mousedown');
662663
fixture.detectChanges();
663664

@@ -675,7 +676,7 @@ describe('CdkDrag', () => {
675676
fixture.detectChanges();
676677

677678
expect(dropZones[0].contains(placeholder))
678-
.toBe(true, 'Expected placeholder to be inside first container.');
679+
.toBe(true, 'Expected placeholder to be back inside first container.');
679680

680681
dispatchMouseEvent(document, 'mouseup');
681682
fixture.detectChanges();
@@ -746,6 +747,46 @@ describe('CdkDrag', () => {
746747
assertDownwardSorting(fixture, Array.from(dropZones[1].querySelectorAll('.cdk-drag')));
747748
}));
748749

750+
it('should be able to return the last item inside its initial container', fakeAsync(() => {
751+
const fixture = createComponent(ConnectedDropZones);
752+
753+
// Make sure there's only one item in the first list.
754+
fixture.componentInstance.todo = ['things'];
755+
fixture.detectChanges();
756+
757+
const groups = fixture.componentInstance.groupedDragItems;
758+
const dropZones = fixture.componentInstance.dropInstances.map(d => d.element.nativeElement);
759+
const item = groups[0][0];
760+
const initialRect = item.element.nativeElement.getBoundingClientRect();
761+
const targetRect = groups[1][0].element.nativeElement.getBoundingClientRect();
762+
763+
expect(dropZones[0].contains(item.element.nativeElement))
764+
.toBe(true, 'Expected placeholder to be inside the first container.');
765+
dispatchMouseEvent(item.element.nativeElement, 'mousedown');
766+
fixture.detectChanges();
767+
768+
const placeholder = dropZones[0].querySelector('.cdk-drag-placeholder')!;
769+
770+
expect(placeholder).toBeTruthy();
771+
772+
dispatchMouseEvent(document, 'mousemove', targetRect.left + 1, targetRect.top + 1);
773+
fixture.detectChanges();
774+
775+
expect(dropZones[1].contains(placeholder))
776+
.toBe(true, 'Expected placeholder to be inside second container.');
777+
778+
dispatchMouseEvent(document, 'mousemove', initialRect.left + 1, initialRect.top + 1);
779+
fixture.detectChanges();
780+
781+
expect(dropZones[0].contains(placeholder))
782+
.toBe(true, 'Expected placeholder to be back inside first container.');
783+
784+
dispatchMouseEvent(document, 'mouseup');
785+
fixture.detectChanges();
786+
787+
expect(fixture.componentInstance.droppedSpy).not.toHaveBeenCalled();
788+
}));
789+
749790
});
750791

751792
});
@@ -916,29 +957,36 @@ export class DraggableInDropZoneWithCustomPlaceholder {
916957

917958

918959
@Component({
960+
encapsulation: ViewEncapsulation.None,
961+
styles: [`
962+
.cdk-drop {
963+
display: block;
964+
width: 100px;
965+
min-height: ${ITEM_HEIGHT}px;
966+
background: hotpink;
967+
}
968+
969+
.cdk-drag {
970+
display: block;
971+
height: ${ITEM_HEIGHT}px;
972+
background: red;
973+
}
974+
`],
919975
template: `
920976
<cdk-drop
921977
#todoZone
922-
style="display: block; width: 100px; background: pink;"
923978
[data]="todo"
924979
[connectedTo]="[doneZone]"
925980
(dropped)="droppedSpy($event)">
926-
<div
927-
*ngFor="let item of todo"
928-
cdkDrag
929-
style="width: 100%; height: ${ITEM_HEIGHT}px; background: red;">{{item}}</div>
981+
<div *ngFor="let item of todo" cdkDrag>{{item}}</div>
930982
</cdk-drop>
931983
932984
<cdk-drop
933985
#doneZone
934-
style="display: block; width: 100px; background: purple;"
935986
[data]="done"
936987
[connectedTo]="[todoZone]"
937988
(dropped)="droppedSpy($event)">
938-
<div
939-
*ngFor="let item of done"
940-
cdkDrag
941-
style="width: 100%; height: ${ITEM_HEIGHT}px; background: green;">{{item}}</div>
989+
<div *ngFor="let item of done" cdkDrag>{{item}}</div>
942990
</cdk-drop>
943991
`
944992
})

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ export class CdkDrag implements AfterContentInit, OnDestroy {
8282
private _activeTransform: Point = {x: 0, y: 0};
8383

8484
/** Whether the element is being dragged. */
85-
private _isDragging = false;
85+
_isDragging = false;
8686

8787
/** Whether the element has moved since the user started dragging it. */
8888
private _hasMoved = false;

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

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,9 @@ export class CdkDrop<T = any> {
141141
const siblings = this._positionCache.items;
142142
const newPosition = siblings.find(({drag, clientRect}) => {
143143
if (drag === item) {
144-
return false;
144+
// If there's only one left item in the container, it must be
145+
// the dragged item itself so we use it as a reference.
146+
return siblings.length < 2;
145147
}
146148

147149
return this.orientation === 'horizontal' ?
@@ -153,7 +155,10 @@ export class CdkDrop<T = any> {
153155
return;
154156
}
155157

156-
const element = newPosition ? newPosition.drag.element.nativeElement : null;
158+
// Don't take the element of a dragged item as a reference,
159+
// because it has been moved down to the end of the body.
160+
const element = (newPosition && !newPosition.drag._isDragging) ?
161+
newPosition.drag.element.nativeElement : null;
157162
const next = element ? element!.nextSibling : null;
158163
const parent = element ? element.parentElement! : this.element.nativeElement;
159164
const placeholder = item.getPlaceholderElement();

0 commit comments

Comments
 (0)