Skip to content

Commit 3b9d6c0

Browse files
crisbetojelbourn
authored andcommitted
fix(drag-drop): item not being restored to its initial DOM position when using custom preview (#12808)
When a `cdkDrag` item is picked up, we save its `nextSibling` so we know where to put it once the user has stopped dragging. This logic gets thrown off when we use a custom preview element and it ends up leaving the element in the wrong place in the DOM. These changes ensure that the element is restored to its old position correctly.
1 parent 36d8412 commit 3b9d6c0

File tree

2 files changed

+24
-1
lines changed

2 files changed

+24
-1
lines changed

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

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -807,6 +807,25 @@ describe('CdkDrag', () => {
807807
expect(preview.textContent!.trim()).toContain('Custom preview');
808808
}));
809809

810+
it('should revert the element back to its parent after dragging with a custom ' +
811+
'preview has stopped', fakeAsync(() => {
812+
const fixture = createComponent(DraggableInDropZoneWithCustomPreview);
813+
fixture.detectChanges();
814+
815+
const dragContainer = fixture.componentInstance.dropInstance.element.nativeElement;
816+
const item = fixture.componentInstance.dragItems.toArray()[1].element.nativeElement;
817+
818+
expect(dragContainer.contains(item)).toBe(true, 'Expected item to be in container.');
819+
820+
// The coordinates don't matter.
821+
dragElementViaMouse(fixture, item, 10, 10);
822+
flush();
823+
fixture.detectChanges();
824+
825+
expect(dragContainer.contains(item))
826+
.toBe(true, 'Expected item to be returned to container.');
827+
}));
828+
810829
it('should position custom previews next to the pointer', fakeAsync(() => {
811830
const fixture = createComponent(DraggableInDropZoneWithCustomPreview);
812831
fixture.detectChanges();

src/cdk/drag-drop/drag.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,14 +262,18 @@ export class CdkDrag<T = any> implements OnDestroy {
262262

263263
if (this.dropContainer) {
264264
const element = this.element.nativeElement;
265+
266+
// Grab the `nextSibling` before the preview and placeholder
267+
// have been created so we don't get the preview by accident.
268+
this._nextSibling = element.nextSibling;
269+
265270
const preview = this._preview = this._createPreviewElement();
266271
const placeholder = this._placeholder = this._createPlaceholderElement();
267272

268273
// We move the element out at the end of the body and we make it hidden, because keeping it in
269274
// place will throw off the consumer's `:last-child` selectors. We can't remove the element
270275
// from the DOM completely, because iOS will stop firing all subsequent events in the chain.
271276
element.style.display = 'none';
272-
this._nextSibling = element.nextSibling;
273277
this._document.body.appendChild(element.parentNode!.replaceChild(placeholder, element));
274278
this._document.body.appendChild(preview);
275279
this.dropContainer.start();

0 commit comments

Comments
 (0)