Reputation:
I am trying out Angular 7 Drag n Drop with a bootstrap grid.
Inside the grid I have panels.
Here is the code:
<div class="container">
<div class="row">
<div class="col-md-4" cdkDropList>
<div class="panel panel-primary" cdkDrag>
<div class="panel-body">
one
</div>
</div>
</div>
<div class="col-md-4" cdkDropList>
<div class="panel panel-primary" cdkDrag>
<div class="panel-body">
two
</div>
</div>
</div>
<div class="col-md-4" cdkDropList>
<div class="panel panel-primary" cdkDrag>
<div class="panel-body">
two
</div>
</div>
</div>
</div>
</div>
I want to be able to move the panels around and maybe sort them and drop the panel in empty grid cells.
My problem is that these panels are stack inside the assigned parent div's and I cannot swap them
How can I get it so I can do this?
Upvotes: 1
Views: 2683
Reputation: 2537
Angular CDK Drag & Drop is based on moving item in array. And that's what you don't do in your example. To make this working in a way you described. You should follow these steps.
First step:
As a first step you should create a @ViewChild
which will get all those cdkDropLists
. Array which will contain your panels
. The last one will be property listsChecked
.
@ViewChildren('list') lists: QueryList<CdkDropList>;
listArray = [[{col: 4, text: 'one'}], [{col: 4, text: 'two'}], [{col: 4, text: 'two'}]];
private listsChecked: boolean = false;
Second step:
Let's change the HTML
template, so it will loop through array you created in a first step. So the HTML
will look like this.
<div class="container">
<div class="row">
<ng-container *ngFor="let listItem of listArray; let i = index">
<div class="list col-md-4">
<div class="list-item panel panel-primary" *ngFor="let item of listItem">
<div class="panel-body">
{{item.text}}
</div>
</div>
</div>
</ng-container>
</div>
</div>
Third step:
To be able to drag and drop update the HTML
template from step 2. Firstly you should add cdkDropListGroup
to .row
. Next add [cdkDropListData]="listItem"
to the <div class="col-md-4"></div>
, to the same element add also this cdkDropList #list="cdkDropList"
this is used for the @ViewChild()
from step 1, again to the same element add (cdkDropListDropped)="drop($event)"
this will call a method always when you drop an item. Also add a cdkDdrag to .panel .panel-primary
. The template should then look like this
<div class="container">
<div class="row" cdkDropListGroup>
<ng-container *ngFor="let listItem of listArray; let i = index">
<div class="list col-md-4" [cdkDropListData]="listItem" cdkDropList #list="cdkDropList"
(cdkDropListDropped)="drop($event)">
<div class="list-item panel panel-primary" *ngFor="let item of listItem" cdkDrag>
<div class="panel-body">
{{item.text}}
</div>
</div>
</div>
</ng-container>
</div>
</div>
Fourth step:
To your *.component.ts
add AfterViewChecked to implements. Into ngAfterViewChecked()
add this code
ngAfterViewChecked() {
if (this.lists.toArray().length > 0 && this.listsChecked === false) {
this.listsChecked = true;
for (let i = 0; i < this.lists.length; i++) {
const array = [];
for (let j = 0; j < this.lists.length; j++) {
if(i !== j) {
array.push(this.lists.toArray()[j]);
}
}
this.lists.toArray()[i].connectedTo = array;
}
}
}
This code will go through all elements with #list
in you template and add every cdkDropList
except him self to cdkDropconnectedTo
<- this is connecting more lists between each other. And add a drop()
method.
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);
}
}
This will check if the destination is is same as a previous container and move as necessary. The drop()
I got from Angular Drag & Drop documentation
Everything should be working the containers will still exists as empty col's. I hope it will help you.
Upvotes: 1