Yassine Zeriouh
Yassine Zeriouh

Reputation: 510

Angular CDK Drag & Drop: Don't move source item

I am trying to implement an editor where one can drag an item to add it to the main content, the problem is that the source item is always destroyed when I'm dragging out of the source item container.

Is there a way to force the source item to stay where it is while it's still possible to drag and drop the item? Basically, I want a copy-behaviour of that instead of a move-behaviour.

I've already seen other questions that correspond to what I want to achieve basically, but none of them really helped me as the questions were more about how to get it technically done to copy an item while I want to know how I implement this behaviour in the UI as its very confusing to see if the item just disappears.

Upvotes: 31

Views: 18948

Answers (4)

Vikas Kandari
Vikas Kandari

Reputation: 1852

All solutions above are great however there is one problem cloning happens after element is dropped so I went through git conversion and found the solution below

STYLES

.drag-container {
    width: 400px;
    max-width: 100%;
    margin: 0 25px 25px 0;
    display: inline-block;
    vertical-align: top;
}

.drag-list {
    border: solid 1px #ccc;
    min-height: 60px;
    background: white;
    border-radius: 4px;
    overflow: hidden;
    display: block;
}

.drag-box {
    padding: 20px 10px;
    border-bottom: solid 1px #ccc;
    color: rgba(0, 0, 0, 0.87);
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    box-sizing: border-box;
    cursor: move;
    background: white;
    font-size: 14px;
}

.cdk-drag-preview {
    box-sizing: border-box;
    border-radius: 4px;
    box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2),
        0 8px 10px 1px rgba(0, 0, 0, 0.14),
        0 3px 14px 2px rgba(0, 0, 0, 0.12);
}

.cdk-drag-placeholder {
    opacity: 0;
}

.cdk-drag-animating {
    transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
}

.drag-box:last-child {
    border: none;
}

.drag-list.cdk-drop-list-dragging .drag-box:not(.cdk-drag-placeholder) {
    transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
}

TYPESCRIPT

menu: any = [
    { title: 'pork', price: 12, id: 1 },
    { title: 'duck', price: 12, id: 2 },
    { title: 'chicken', price: 12, id: 3 },
    { title: 'beef', price: 12, id: 4 },
    { title: 'soup', price: 12, id: 5 },
  ];

  table: any = [];



  drop(event: any) {
    if (event.previousContainer !== event.container) {
      copyArrayItem(
        event.previousContainer.data,
        event.container.data,
        event.previousIndex,
        event.currentIndex
      );
    } else {
      moveItemInArray(
        event.container.data,
        event.previousIndex,
        event.currentIndex
      );
    }
    if (event.previousContainer.data) {
      this.menu = this.menu.filter((f: any) => !f.temp);
    }
  }



  exited(event: any) {
    const currentIdx = event.container.data.findIndex(
      (f: any) => f.id === event.item.data.id
    );
    this.menu.splice(currentIdx + 1, 0, {
      ...event.item.data,
      temp: true,
    });
  }
  entered() {
    this.menu = this.menu.filter((f: any) => !f.temp);
  }

HTML

<div cdkDropListGroup>
            <div class="drag-container">
                <h2>To do</h2>
                <div class="drag-list" cdkDropList #menuList="cdkDropList" [cdkDropListData]="menu" cdkDropListSortingDisabled [cdkDropListConnectedTo]="[tableList]" (cdkDropListDropped)="drop($event)" (cdkDropListExited)="exited($event)" (cdkDropListEntered)="entered()">
                    <div class="drag-box" *ngFor="let item of menu" cdkDrag [cdkDragData]="item">{{item.title}}</div>
                </div>
            </div>
            <div class="drag-container">
                <h2>Done</h2>
                <div class="drag-list" cdkDropList #tableList="cdkDropList" [cdkDropListData]="table" (cdkDropListDropped)="drop($event)">
                    <div class="drag-box" *ngFor="let item of table; let idx = index" cdkDrag>{{item.title}}</div>
                </div>
            </div>
</div>

Source 1 : stackblitz

Source 2 : github

Upvotes: 9

Najim Ali
Najim Ali

Reputation: 201

You need to find location of target & source then copy the value

Case 1: Copy from one draggable list to another draggable list

   drop(event: any) {
        if (event.previousContainer === event.container) {
              moveItemInArray(
                event.container.data,
                event.previousIndex,
                event.currentIndex
              );
            } else {

              const prev_idx = event.previousIndex;
              const curr_id = event.currentIndex;
              // Copy the data.
              event.container.data[curr_id] = event.previousContainer.data[prev_idx];
        
            }
          }
    }

Case 2: Copy your Data from list to a specific variable

drop(event: any) {
          // Copy the data to my-variable
                  const prev_idx = event.previousIndex;    
                  this.my-variable = event.previousContainer.data[prev_idx];
            
                }
              }
        }

Upvotes: 0

TRIKONINFOSYSTEMS
TRIKONINFOSYSTEMS

Reputation: 640

Import import {copyArrayItem} from '@angular/cdk/drag-drop';

AND

Replace transferArrayItem with copyArrayItem

Upvotes: 7

arpit tayal
arpit tayal

Reputation: 336

replace

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
    );
  }
}

with

drop(event: any) {
  if (event.previousContainer === event.container) {
    moveItemInArray(event.container.data, event.previousIndex, event.currentIndex);
  } else {
    copyArrayItem(
      event.previousContainer.data,
      event.container.data,
      event.previousIndex,
      event.currentIndex
    );
  }
}

Upvotes: 30

Related Questions