Is there a way to dynamically create drop zones? I\'m having some troubles with ngFor and cdkDropList.
Here is my first list and draggable elements:
After a full day of research, I found this pull request on Angular CDK repository on Github. Now, since I did not know how to integrate cdkDropListGroup into my example, I decited to create an array of IDs which will be added to [cdkDropListConnectedTo].
Each instance of my second list will have generated ID, and that ID will be added to array with suitable prefix (in my second list, on cdkDropList):
<div cdkDropList
[attr.id]="addId(i, j)"
[cdkDropListData]="appointment.lessons"
[cdkDropListConnectedTo]="[subjectList]"
(cdkDropListDropped)="drop($event)"
>
addId method:
addId(i, j) {
this.LIST_IDS.push('cdk-drop-list-' + i + '' + j);
return i + '' + j;
}
(cdk-drop-list- is an ID prefix. CDK places this prefix on every element with cdkDropList attribute)
So, my array will look like:
Now, I pass that array to [cdkDropListConnectedTo] in my first list:
<div class="subj-container"
cdkDropListOrientation="horizontal"
cdkDropList
#subjectList="cdkDropList"
[cdkDropListData]="subjects"
[cdkDropListConnectedTo]="LIST_IDS"
(cdkDropListDropped)="drop($event)"
>
And it works flawlessly!
Hope this will help anybody with the same problem. Also, take a look at the pull request I mentioned, my solution is only a workaround, there is probably a better solution with cdkDropListGroup
A bit late, but Helpful and worth sharing. I've created a kanban board using angular material version 10. Here is the link to the demo. https://stackblitz.com/edit/angular-material-kanban
Source Link
Demo Link
For Dynamic Drag n Drop Lists, we can use ID instead of # Template variables
app.component.html
<div class="col-md-3" *ngFor="let week of weeks">
<div class="drag-container">
<div class="section-heading">Week {{week.id}}</div>
<div cdkDropList id="{{week.id}}" [cdkDropListData]="week.weeklist"
[cdkDropListConnectedTo]="connectedTo" class="item-list" (cdkDropListDropped)="drop($event)">
<div class="item-box" *ngFor="let weekItem of week.weeklist" cdkDrag>Week {{week.id}} {{weekItem}}</div>
</div>
</div>
</div>
app.component.ts
import { Component } from '@angular/core';
import { CdkDragDrop, moveItemInArray, transferArrayItem } from '@angular/cdk/drag-drop';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
weeks = [];
connectedTo = [];
constructor() {
this.weeks = [
{
id: 'week-1',
weeklist: [
"item 1",
"item 2",
"item 3",
"item 4",
"item 5"
]
}, {
id: 'week-2',
weeklist: [
"item 1",
"item 2",
"item 3",
"item 4",
"item 5"
]
}, {
id: 'week-3',
weeklist: [
"item 1",
"item 2",
"item 3",
"item 4",
"item 5"
]
}, {
id: 'week-4',
weeklist: [
"item 1",
"item 2",
"item 3",
"item 4",
"item 5"
]
},
];
for (let week of this.weeks) {
this.connectedTo.push(week.id);
};
}
drop(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);
}
}
}
I've built a stackblitz example using a dynamic group of lists and cdkDropListGroup. I'm memorizing the first list's name on the item in the list. By memorizing the first list I can track which objects have changed, which can be handy for building some cases. It also gives me the possibility to change the background color of the items that have moved, clearly showing what's changed.
I had also to face to that problem. I tried the id approach but I didn't feel too much too confident while using. When I console.log in this addId() function, I can see the same id repeated several times. Instead of that, I tried to use the @ViewChildren decorator to have the cdkList components in real time, and it works very well for me.
In typescript
cdkDropTrackLists: CdkDropList[];
@ViewChildren(CdkDropList)
set cdkDropLists(value: QueryList<CdkDropList>) {
this.cdkDropTrackLists = value.toArray();
}
In template
<div
cdkDropList
class="track-list"
cdkDropListSortingDisabled
[cdkDropListData]="paragraphIdentifiers"
(cdkDropListDropped)="drop($event)"
[cdkDropListConnectedTo]="cdkDropTrackLists">
</div>
I think I can improve it while cdkDropLists as a QueryList has a changes properties which an Observable.
With cdkDropListGroup you can now do:
<div cdkDropListGroup>
<div cdkDropList
[cdkDropListData]="data"
(cdkDropListDropped)="drop($event)">
<div class="row m-2">
<div *ngFor="let i of data cdkDrag>{{i}}</div>
</div>
</div>
<div class="subj-container"
cdkDropListOrientation="horizontal"
cdkDropList
#subjectList="cdkDropList"
[cdkDropListData]="subjects"
(cdkDropListDropped)="drop($event)">
</div>
</div>
No longer a need for cdkDropListConnectedTo in this case. See https://github.com/angular/material2/blob/master/src/cdk/drag-drop/drag-drop.md