Skip to content

Commit 92aed70

Browse files
crisbetojelbourn
authored andcommitted
fix(drag-drop): handle custom preview/placeholder with multiple root nodes (#18829)
We support passing in a custom preview or placeholder using an `ng-template`, but we were only taking the first `rootNode` from the template. (cherry picked from commit 8a71288)
1 parent 0268117 commit 92aed70

File tree

2 files changed

+77
-6
lines changed

2 files changed

+77
-6
lines changed

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

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2978,6 +2978,21 @@ describe('CdkDrag', () => {
29782978
expect(preview.textContent!.trim()).toContain('Hello One');
29792979
}));
29802980

2981+
it('should handle custom preview with multiple root nodes', fakeAsync(() => {
2982+
const fixture = createComponent(DraggableInDropZoneWithCustomMultiNodePreview);
2983+
fixture.detectChanges();
2984+
const item = fixture.componentInstance.dragItems.toArray()[1].element.nativeElement;
2985+
2986+
expect(() => {
2987+
startDraggingViaMouse(fixture, item);
2988+
}).not.toThrow();
2989+
2990+
const preview = document.querySelector('.cdk-drag-preview')! as HTMLElement;
2991+
2992+
expect(preview).toBeTruthy();
2993+
expect(preview.textContent!.trim()).toContain('HelloOne');
2994+
}));
2995+
29812996
it('should be able to customize the placeholder', fakeAsync(() => {
29822997
const fixture = createComponent(DraggableInDropZoneWithCustomPlaceholder);
29832998
fixture.detectChanges();
@@ -3050,6 +3065,21 @@ describe('CdkDrag', () => {
30503065
expect(placeholder.textContent!.trim()).toContain('Hello One');
30513066
}));
30523067

3068+
it('should handle custom placeholder with multiple root nodes', fakeAsync(() => {
3069+
const fixture = createComponent(DraggableInDropZoneWithCustomMultiNodePlaceholder);
3070+
fixture.detectChanges();
3071+
const item = fixture.componentInstance.dragItems.toArray()[1].element.nativeElement;
3072+
3073+
expect(() => {
3074+
startDraggingViaMouse(fixture, item);
3075+
}).not.toThrow();
3076+
3077+
const placeholder = document.querySelector('.cdk-drag-placeholder')! as HTMLElement;
3078+
3079+
expect(placeholder).toBeTruthy();
3080+
expect(placeholder.textContent!.trim()).toContain('HelloOne');
3081+
}));
3082+
30533083
it('should clear the `transform` value from siblings when item is dropped`', fakeAsync(() => {
30543084
const fixture = createComponent(DraggableInDropZone);
30553085
fixture.detectChanges();
@@ -5192,6 +5222,28 @@ class DraggableInDropZoneWithCustomTextOnlyPreview {
51925222
}
51935223

51945224

5225+
@Component({
5226+
template: `
5227+
<div cdkDropList style="width: 100px; background: pink;">
5228+
<div
5229+
*ngFor="let item of items"
5230+
cdkDrag
5231+
style="width: 100%; height: ${ITEM_HEIGHT}px; background: red;">
5232+
{{item}}
5233+
<ng-template cdkDragPreview>
5234+
<span>Hello</span>
5235+
<span>{{item}}</span>
5236+
</ng-template>
5237+
</div>
5238+
</div>
5239+
`
5240+
})
5241+
class DraggableInDropZoneWithCustomMultiNodePreview {
5242+
@ViewChild(CdkDropList) dropInstance: CdkDropList;
5243+
@ViewChildren(CdkDrag) dragItems: QueryList<CdkDrag>;
5244+
items = ['Zero', 'One', 'Two', 'Three'];
5245+
}
5246+
51955247
@Component({
51965248
template: `
51975249
<div
@@ -5240,6 +5292,25 @@ class DraggableInDropZoneWithCustomTextOnlyPlaceholder {
52405292
items = ['Zero', 'One', 'Two', 'Three'];
52415293
}
52425294

5295+
@Component({
5296+
template: `
5297+
<div cdkDropList style="width: 100px; background: pink;">
5298+
<div *ngFor="let item of items" cdkDrag
5299+
style="width: 100%; height: ${ITEM_HEIGHT}px; background: red;">
5300+
{{item}}
5301+
<ng-template cdkDragPlaceholder>
5302+
<span>Hello</span>
5303+
<span>{{item}}</span>
5304+
</ng-template>
5305+
</div>
5306+
</div>
5307+
`
5308+
})
5309+
class DraggableInDropZoneWithCustomMultiNodePlaceholder {
5310+
@ViewChildren(CdkDrag) dragItems: QueryList<CdkDrag>;
5311+
items = ['Zero', 'One', 'Two', 'Three'];
5312+
}
5313+
52435314
const CONNECTED_DROP_ZONES_STYLES = [`
52445315
.cdk-drop-list {
52455316
display: block;

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

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1297,15 +1297,15 @@ function getPreviewInsertionPoint(documentRef: any): HTMLElement {
12971297
* If the root is not an HTML element it gets wrapped in one.
12981298
*/
12991299
function getRootNode(viewRef: EmbeddedViewRef<any>, _document: Document): HTMLElement {
1300-
const rootNode: Node = viewRef.rootNodes[0];
1300+
const rootNodes: Node[] = viewRef.rootNodes;
13011301

1302-
if (rootNode.nodeType !== _document.ELEMENT_NODE) {
1303-
const wrapper = _document.createElement('div');
1304-
wrapper.appendChild(rootNode);
1305-
return wrapper;
1302+
if (rootNodes.length === 1 && rootNodes[0].nodeType === _document.ELEMENT_NODE) {
1303+
return rootNodes[0] as HTMLElement;
13061304
}
13071305

1308-
return rootNode as HTMLElement;
1306+
const wrapper = _document.createElement('div');
1307+
rootNodes.forEach(node => wrapper.appendChild(node));
1308+
return wrapper;
13091309
}
13101310

13111311
/**

0 commit comments

Comments
 (0)