user10044012
user10044012

Reputation:

Angular 7 Drag n drop in grid not able to move panels between grid

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

Answers (1)

joka00
joka00

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 cdkDropListexcept 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

Related Questions