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

4

30

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.

Nenitanenney answered 13/5, 2019 at 13:57 Comment(1)
Possible duplicate of Drag Drop CDK: keep showing dragged element inside starting listVoroshilovgrad
L
29

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
    );
  }
}
Least answered 6/2, 2020 at 6:29 Comment(2)
Thanks for this solution. However, with this behaviour, there is a style issue on the list from which are moving the element. It fluctuates the list as it looks like it removes and then adds the element on the list for the copy operation. Please refer to this stackblitz link - stackblitz.com/edit/…Procrustean
Yes, do we even need copyArrayItem? I've got this working with the same UX by simply NOT updating the source list in the drop method. Agreed, the visual style of dragging OUT is the issue.Disembarrass
E
7

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

Excitant answered 15/8, 2022 at 14:26 Comment(1)
+1 This solution better answers the original question. Using Exited and Entered events makes for a smoother ux.Thundersquall
W
6

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

AND

Replace transferArrayItem with copyArrayItem

Waterside answered 21/9, 2020 at 7:58 Comment(0)
A
0

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];
            
                }
              }
        }
Amends answered 18/2, 2021 at 7:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.