diff --git a/src/cdk/drag-drop/drag-drop.md b/src/cdk/drag-drop/drag-drop.md index 3a5764949fcb..e15b5de4c70f 100644 --- a/src/cdk/drag-drop/drag-drop.md +++ b/src/cdk/drag-drop/drag-drop.md @@ -100,7 +100,10 @@ restrict the user to only be able to do so using a handle element, you can do it ### Customizing the drag preview When a `cdkDrag` element is picked up, it will create a preview element visible while dragging. By default, this will be a clone of the original element positioned next to the user's cursor. -This preview can be customized, though, by providing a custom template via `*cdkDragPreview`: +This preview can be customized, though, by providing a custom template via `*cdkDragPreview`. +Note that the cloned element will remove its `id` attribute in order to avoid having multiple +elements with the same `id` on the page. This will cause any CSS that targets that `id` not +to be applied. diff --git a/src/cdk/drag-drop/drag.spec.ts b/src/cdk/drag-drop/drag.spec.ts index d131461ed73e..1d270edebec4 100644 --- a/src/cdk/drag-drop/drag.spec.ts +++ b/src/cdk/drag-drop/drag.spec.ts @@ -831,6 +831,19 @@ describe('CdkDrag', () => { expect(preview.parentNode).toBeFalsy('Expected preview to be removed from the DOM'); })); + it('should clear the id from the preview', fakeAsync(() => { + const fixture = createComponent(DraggableInDropZone); + fixture.detectChanges(); + const item = fixture.componentInstance.dragItems.toArray()[1].element.nativeElement; + item.id = 'custom-id'; + + startDraggingViaMouse(fixture, item); + + const preview = document.querySelector('.cdk-drag-preview')! as HTMLElement; + + expect(preview.getAttribute('id')).toBeFalsy(); + })); + it('should not create a preview if the element was not dragged far enough', fakeAsync(() => { const fixture = createComponent(DraggableInDropZone, [], 5); fixture.detectChanges(); @@ -988,6 +1001,20 @@ describe('CdkDrag', () => { expect(placeholder.parentNode).toBeFalsy('Expected placeholder to be removed from the DOM'); })); + it('should remove the id from the placeholder', fakeAsync(() => { + const fixture = createComponent(DraggableInDropZone); + fixture.detectChanges(); + const item = fixture.componentInstance.dragItems.toArray()[1].element.nativeElement; + + item.id = 'custom-id'; + + startDraggingViaMouse(fixture, item); + + const placeholder = document.querySelector('.cdk-drag-placeholder')! as HTMLElement; + + expect(placeholder.getAttribute('id')).toBeFalsy(); + })); + it('should not create placeholder if the element was not dragged far enough', fakeAsync(() => { const fixture = createComponent(DraggableInDropZone, [], 5); fixture.detectChanges(); diff --git a/src/cdk/drag-drop/drag.ts b/src/cdk/drag-drop/drag.ts index 35c9a5f29eac..a1c2fedd25c5 100644 --- a/src/cdk/drag-drop/drag.ts +++ b/src/cdk/drag-drop/drag.ts @@ -566,7 +566,7 @@ export class CdkDrag implements AfterViewInit, OnDestroy { const element = this._rootElement; const elementRect = element.getBoundingClientRect(); - preview = element.cloneNode(true) as HTMLElement; + preview = deepCloneNode(element); preview.style.width = `${elementRect.width}px`; preview.style.height = `${elementRect.height}px`; preview.style.transform = getTransform(elementRect.left, elementRect.top); @@ -596,7 +596,7 @@ export class CdkDrag implements AfterViewInit, OnDestroy { ); placeholder = this._placeholderRef.rootNodes[0]; } else { - placeholder = this._rootElement.cloneNode(true) as HTMLElement; + placeholder = deepCloneNode(this._rootElement); } placeholder.classList.add('cdk-drag-placeholder'); @@ -803,3 +803,11 @@ interface Point { function getTransform(x: number, y: number): string { return `translate3d(${x}px, ${y}px, 0)`; } + +/** Creates a deep clone of an element. */ +function deepCloneNode(node: HTMLElement): HTMLElement { + const clone = node.cloneNode(true) as HTMLElement; + // Remove the `id` to avoid having multiple elements with the same id on the page. + clone.removeAttribute('id'); + return clone; +}