0

I'm creating a simple drag&drop application in angular using angular CDK. I just want to drag my box and drop it to another box. But when releasing the dragged box inside the dropped area, I'm getting the error. Kindly help fixing it.

Error I'm getting

Unhandled Promise rejection: Failed to execute 'appendChild' on 'Node': The new child element contains the parent. ; Zone: <root> ; Task: Promise.then ; Value: DOMException: Failed to execute 'appendChild' on 'Node': The new child element contains the parent.
    at DragRef._cleanupDragArtifacts (http://localhost:4200/vendor.js:1615:121)
    at http://localhost:4200/vendor.js:1471:22
    at ZoneDelegate.invoke (http://localhost:4200/polyfills.js:3365:26)
    at Zone.run (http://localhost:4200/polyfills.js:3130:43)
    at http://localhost:4200/polyfills.js:3861:36
    at ZoneDelegate.invokeTask (http://localhost:4200/polyfills.js:3397:31)
    at Zone.runTask (http://localhost:4200/polyfills.js:3174:47)
    at drainMicroTaskQueue (http://localhost:4200/polyfills.js:3565:35)
    at ZoneTask.invokeTask [as invoke] (http://localhost:4200/polyfills.js:3475:21)
    at invokeTask (http://localhost:4200/polyfills.js:4609:14) Error: Failed to execute 'appendChild' on 'Node': The new child element contains the parent.
    at DragRef._cleanupDragArtifacts (http://localhost:4200/vendor.js:1615:121)
    at http://localhost:4200/vendor.js:1471:22
    at ZoneDelegate.invoke (http://localhost:4200/polyfills.js:3365:26)
    at Zone.run (http://localhost:4200/polyfills.js:3130:43)
    at http://localhost:4200/polyfills.js:3861:36
    at ZoneDelegate.invokeTask (http://localhost:4200/polyfills.js:3397:31)
    at Zone.runTask (http://localhost:4200/polyfills.js:3174:47)
    at drainMicroTaskQueue (http://localhost:4200/polyfills.js:3565:35)
    at ZoneTask.invokeTask [as invoke] (http://localhost:4200/polyfills.js:3475:21)
    at invokeTask (http://localhost:4200/polyfills.js:4609:14)
api.onUnhandledError @ zone-evergreen.js:651
handleUnhandledRejection @ zone-evergreen.js:675
api.microtaskDrainDone @ zone-evergreen.js:668
drainMicroTaskQueue @ zone-evergreen.js:566
invokeTask @ zone-evergreen.js:469
invokeTask @ zone-evergreen.js:1603
globalZoneAwareCallback @ zone-evergreen.js:1629

And I will paste my code below

My app.component.html

<section>
  <div class="wrapper">
    <div class="outerBox">
        <div class="innerBox" cdkDropList [cdkDropListConnectedTo]="[dropZone]" cdkDrag></div>
    </div>

    <div class="outerBox" #dropZone="cdkDropList" cdkDropList (cdkDropListDropped)="onItemDrop($event)">
    </div>
  </div>
</section>

and app.component.ts

import { Component } from '@angular/core';
import {CdkDragDrop, moveItemInArray, transferArrayItem} from '@angular/cdk/drag-drop';
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {

  onItemDrop(event) {
    console.log(event);
  }
}

and app.component.css file look like

.wrapper {
    display: flex;
}
.outerBox {
    width: 300px;
    height: 500px;
    border: 1px solid #333;
    padding: 10px;
    margin: 10px;
}
.innerBox {
    width: 100px;
    height: 100px;
    background: skyblue;
}

Kindly help in solving the error.

Thanks in advance.

Manush
  • 1,852
  • 7
  • 26
  • 39
  • You can refer - https://stackoverflow.com/questions/25216460/failed-to-execute-appendchild-on-node-the-new-child-element-is-null . Hope it helps – Krunal Shah Nov 05 '19 at 07:02
  • Yeah, I too checked that. Its solution for javascript but I need a fix for angular drag & drop cdk. – Manush Nov 05 '19 at 07:11
  • This will help for sure - https://material.angular.io/cdk/drag-drop/overview – Krunal Shah Nov 05 '19 at 07:15
  • I have created stackblitz for issue reproduction. You can check the console after dropping the bluebox. https://stackblitz.com/edit/angular-ebfpvj – Manush Nov 05 '19 at 09:34

2 Answers2

0

You need to define separate lists in your .ts file for storing the data e.g.

  list1 = ['hello1'];
  list2 = [];

In the .ts file in your onItemDrop function you also need to provide the code for transferring the data:

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

Then this code will work in your .html file:

<section>
    <div class="wrapper">
      <div class="outerBox" [cdkDropListData]="list1" id="dropZone1" cdkDropList [cdkDropListConnectedTo]="'dropZone2'" (cdkDropListDropped)="onItemDrop($event)">
          <div *ngFor="let item of list1" class="innerBox" cdkDrag></div>
      </div>
      <div class="outerBox" [cdkDropListData]="list2" id="dropZone2" [cdkDropListConnectedTo]="'dropZone1'" cdkDropList (cdkDropListDropped)="onItemDrop($event)">
        <div *ngFor="let item of list2" class="innerBox" cdkDrag></div>
      </div>
    </div>
</section>

In the above HTML, I fixed the following:

  • Separate the cdkDropList from the cdkDrag element.
  • Specify the connected ids correctly.
  • Use an *ngFor to iterate over the data to be displayed.
user2846469
  • 2,072
  • 3
  • 18
  • 32
0

Here steps you can follow to get started.

In Component class

  1. Define the 2 lists to connected each other.
  2. And implement moveItemInArray and transferArrayItem cdk helper methods: the first method is to handle change index in each list. And the second to handle transfer from list to an other list.

In template:

  1. Bind each list to a reference or id (e.g #listRef) container
  2. add cdkDropList, cdkDropListData, cdkDropListConnectedTo directives for each one
  3. add method to listen when cdkDropListDropped for both lists, here "onItemDrop"
  4. Iterate on each list with cdkDrag directive on each draggble item

I prepared a working stackblitz example.

akramgassem
  • 111
  • 2
  • 9