CDK Drag&Drop nested lists

788 views Asked by At

I have two objects, Users and Info.

I intend to present users in different columns (individualize them) and within each User I intend to put the respective information where the User ID is the same as the IDUser in the info object. Basically, I intend to present the Obejto Info information within the list of each user, respectively.

At the moment I have two lists (users and info) I want to drag and drop between placing them vertically and horizontally, but without success.

Someone can help me solve this problem in order to pass the cards from one column to another (from user to user).

Example: In the column named Name1 I intend to place the card with the text Expand in the column named Name2.

Thank you

DEMO

IMG

html

<div style="width:100%; height:100%; display:flex; justify-content:center">
<div *ngFor="let usr of Users" style="width: 20%;">
  <div class="card">
    <div class="card-header" style="display: flex; align-items: center; justify-content: center;">
      <span>{{usr.name}}</span>
    </div>
    <div class="card-body" style="height:100%" cdkDropList
      cdkDropListOrientation="vertical" [cdkDropListData]="Info"
      (cdkDropListDropped)="drop($event)">    
      <div *ngFor="let item of Info">
        <div *ngIf="usr.id == item.idUser" cdkDrag>
          <div class="card">
            <div class="card-header" style="padding: 0px;">
             <span>{{item.text}}</span>
            </div>
            <div class="card-body" style="padding: 0px;position: relative;">
          <span>{{item.text}}</span>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>
</div>

.ts

  Users = [
    { id: 1, name: "Name1" },
    { id: 2, name: "Name2" },
    { id: 3, name: "Name3" }
  ];

  Info = [
    { idUser: 1, text: "Expand1" },
    { idUser: 1, text: "Expand11" },
    { idUser: 2, text: "Expand2" },
    { idUser: 2, text: "Expand22" },
    { idUser: 3, text: "Expand33" },
    { idUser: 3, text: "Expand33" }
  ];

  drop(event: CdkDragDrop<string[]>) {
    console.log("TO", event.previousContainer.data[event.previousIndex]);
    console.log("FROM", event.previousContainer.data[event.currentIndex]);
    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
      );
    }
  }
1

There are 1 answers

1
Dipen Shah On BEST ANSWER

You can do multiple changes to your approach to solve this issue:

  1. You technically just have a single data source for data and that will not work so transform your data structure so that each user will have an array to UserInfo items.
  2. Use cdkDropListGroup on container element which contains all cdkDropList

and that's all!

import {
  Component
} from "@angular/core";
import {
  CdkDragDrop,
  moveItemInArray,
  transferArrayItem
} from "@angular/cdk/drag-drop";

@Component({
  selector: "my-app",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.css"]
})
export class AppComponent {
  Users = [{
      id: 1,
      name: "Name1",
      items: [{
        idUser: 1,
        text: "Expand1"
      }, {
        idUser: 1,
        text: "Expand11"
      }]
    },
    {
      id: 2,
      name: "Name2",
      items: [{
        idUser: 2,
        text: "Expand2"
      }, {
        idUser: 2,
        text: "Expand22"
      }]
    },
    {
      id: 3,
      name: "Name3",
      items: [{
        idUser: 3,
        text: "Expand33"
      }, {
        idUser: 3,
        text: "Expand33"
      }]
    }
  ];

  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
      );
    }
  }
}
<div style="width:100%; height:100%; display:flex; justify-content:center" cdkDropListGroup>
  <div *ngFor="let usr of Users" style="width: 20%;">
    <div class="card">
      <div class="card-header" style="display: flex; align-items: center; justify-content: center;">
        <span>{{usr.name}}</span>
      </div>
      <div class="card-body" style="height:100%" cdkDropList id="{{usr.id}}" cdkDropListOrientation="vertical" [cdkDropListData]="usr.items" (cdkDropListDropped)="drop($event)">
        <div *ngFor="let item of usr.items">
          <div cdkDrag>
            <div class="card">
              <div class="card-header" style="padding: 0px;">
                <span>{{item.text}}</span>
              </div>
              <div class="card-body" style="padding: 0px;position: relative;">
                <span>{{item.text}}</span>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>

Take a look at this stackblitz forked from yours.