Update:
I've created a stackblitz to reproduce the problem.
Consider the following static template I have:
<div class="websiteleftColumn" cdkDropList #left="cdkDropList"
[cdkDropListConnectedTo]="[right]">
<div class="panelWithMuchContent" cdkDrag> much HTML </div>
<div class="panelWithMuchContent" cdkDrag> much HTML </div>
<div class="panelWithMuchContent" cdkDrag> much HTML </div>
</div>
<div class="websiteRightColumn" cdkDropList #right="cdkDropList"
[cdkDropListConnectedTo]="[left]">
<div class="panelWithMuchContent" cdkDrag> much HTML </div>
<div class="panelWithMuchContent" cdkDrag> much HTML </div>
<div class="panelWithMuchContent" cdkDrag> much HTML </div>
</div>
I would expect to be able to freely reorder the panels in both columns and also between the two. Instead, I'm able to drag the panels, but as soon as I drop one, nothing happens, it moves back to its original state.
A guess it's because there is no data model behind. In the examples, the draggable divs are rendered on the page by *ngFor
from an array. And there's also a drop(event: CdkDragDrop<string[]>)
component method bound to them that updates the data model every time a drop happens.
But my problem is that I don't just have so simple list elements that I could put in some array, but entire parts of the website with much HTML code inside that I want to drag.
How could I create a data model for it? (if it's really that Angular's missing)
See this answer for the reason why it was not working and here's also an example how drag and drop is properly implemented using ng-template
s and a data model:
import { Component, Input, ViewChild, TemplateRef } from '@angular/core';
import { CdkDragDrop, moveItemInArray, transferArrayItem } from '@angular/cdk/drag-drop';
@Component({
selector: 'hello',
template: `
<div class="row" cdkDropListGroup>
<div class="col-6" cdkDropList [cdkDropListData]="list1"
(cdkDropListDropped)="panelDropped($event)">
<div cdkDrag *ngFor="let p of list1">
<ng-container *ngTemplateOutlet="this[p+'Panel']">
</ng-container>
</div>
</div>
<div class="col-6" cdkDropList [cdkDropListData]="list2"
(cdkDropListDropped)="panelDropped($event)">
<div cdkDrag *ngFor="let p of list2">
<ng-container *ngTemplateOutlet="this[p+'Panel']">
</ng-container>
</div>
</div>
</div>
<ng-template #aPanel><div class="card"></div></ng-template>
<ng-template #bPanel><div class="card"></div></ng-template>
<ng-template #cPanel><div class="card"></div></ng-template>
<ng-template #dPanel><div class="card"></div></ng-template>
<ng-template #ePanel><div class="card"></div></ng-template>
<ng-template #fPanel><div class="card"></div></ng-template>
`,
styles: [`
.col-6:nth-child(1) { background-color: plum; }
.col-6:nth-child(2) { background-color: peru; }
.card { background-color: blue; height: 10em; margin: 0.5em; }
`]
})
export class HelloComponent {
@Input() name: string;
@ViewChild('aPanel') aPanel: TemplateRef<any>;
@ViewChild('bPanel') bPanel: TemplateRef<any>;
@ViewChild('cPanel') cPanel: TemplateRef<any>;
@ViewChild('dPanel') dPanel: TemplateRef<any>;
@ViewChild('ePanel') ePanel: TemplateRef<any>;
@ViewChild('fPanel') fPanel: TemplateRef<any>;
list1: Array<string> = ['a', 'b', 'c'];
list2: Array<string> = ['d', 'e', 'f'];
panelDropped(event: CdkDragDrop<string[]>) {
if (event.previousContainer === event.container) {
moveItemInArray(event.container.data,
event.previousIndex, event.currentIndex);
} else {
transferArrayItem(event.previousContainer.data,
event.container.data, event.previousIndex, event.currentIndex);
}
}
}