37

As recently angular introduced drag and drop in angular material https://material.angular.io/cdk/drag-drop/overview .

All examples describes with in a single component. How to use this in two different components, Drag one component item and drop into another component.

Jomy Joseph
  • 473
  • 1
  • 4
  • 6

5 Answers5

40

You may use properties id and cdkDropListConnectedTo to link both lists:

Component 1:

<div cdkDropList id="list-1" cdkDropListConnectedTo="list-2" (cdkDropListDropped)="drop($event)">
    <div *ngFor="let item of list" cdkDrag>{{ item }}</div>
</div>

Component 2:

<div cdkDropList id="list-2" cdkDropListConnectedTo="list-1" (cdkDropListDropped)="drop($event)">
  <div *ngFor="let item of list" cdkDrag>{{ item }}</div>
</div>

If you need to connect several lists to one list, you may use the following syntax: [cdkDropListConnectedTo]="['list-1', 'list-2', 'list-3', 'list-4']"

After linking the lists, you must correctly update one or both lists depending on the actions. You may do it on the drop function like this:

drop(event: CdkDragDrop<string[]>) {
    if (event.container.id === event.previousContainer.id) {
      // move inside same list
      moveItemInArray(this.list, event.previousIndex, event.currentIndex);
    } else {
      // move between lists
    }
}

For moving items between lists, you will possibly want to keep track of the lists centrally. You may do so by using a Service, a Store or other methods.

GCSDC
  • 3,138
  • 3
  • 28
  • 48
  • Thank you. This is coming fine for single drag block, if I want multiple like [cdkDropListConnectedTo]="[list-2,list-3,list-4] is not working. how to achive that – Jomy Joseph Nov 22 '18 at 10:02
  • 1
    @JomyJoseph I've updated the answer to include support for linking between multiple lists. If this solves your issue, please accept the answer. If not, let us know. – GCSDC Nov 22 '18 at 15:12
  • Sure. You are rock. I missed single quote for each id. – Jomy Joseph Nov 22 '18 at 15:58
  • in angular 7.2.1 i had to use [] around cdkDropListConnectedTo to work even with one list. `[cdkDropListConnectedTo]="[list-1]"` or `[cdkDropListConnectedTo]="['list-1']"` – deelde Jan 15 '19 at 14:04
  • @Dirk tested it with angular 7.2.0 and angular material/cdk 7.2.1 and it worked using the same syntax as before: `cdkDropListConnectedTo="list-1"` – GCSDC Jan 15 '19 at 20:39
  • @GCSDC sorry, you're right. Tested right now and it works. don't know what was the mistake yesterday. – deelde Jan 16 '19 at 06:28
  • You saved my life sir. The Angular examples do not include the `id=""`-part, which was missing for me. – Spray'n'Pray Apr 23 '21 at 12:17
  • Hi man, and how would it be done to drag the columns, in the case of "MOVIES WATCHED", "MOVIE"? https://stackoverflow.com/questions/72437853/angular-cdk-drag-with-two-lists?noredirect=1#comment127968880_72437853 – Rod May 31 '22 at 14:15
13

Not sure if the above solution still works with angular 7.2.9 and angular material/cdk 7.3.5

It did not work for me and thus after some hard time - I managed to make it work using cdkDropListGroup directive. All cdkDropList within cdkDropListGroup will be available to drop items. You no longer need to connect Drop Lists with cdkDropListConnectedTo property

<div cdkDropListGroup>
<component1></component1>
<component2></component2>
</div>
Alty
  • 131
  • 2
  • 2
10

You just need to create a drop method in the service and call that drop method from two components. And have to wrap these two components with cdkDropListGroup on the parent component.

App Component

<div class="wrapper">
  <div cdkDropListGroup>
    <app-test1></app-test1>
    <app-test2></app-test2>
  </div>
</div>

Test1 Component

<div class="container">
  <h2>Movies</h2>
  <div cdkDropList [cdkDropListData]="MoviesList"
    class="movie-list" (cdkDropListDropped)="onDrop($event)">
    <div class="movie-block" *ngFor="let moviesList of MoviesList" cdkDrag>{{moviesList}}</div>
  </div>
</div>

  export class Test1Component implements OnInit {

  constructor(private ss: ShareService) { }

  ngOnInit() {
  }

  // Transfer Items Between Lists
  MoviesList = [
    'The Far Side of the World',
    'Morituri',
    'Napoleon Dynamite',
    'Pulp Fiction',
    'Blade Runner',
    'Cool Hand Luke',
    'Heat',
    'Juice'    
  ];


  onDrop(event: CdkDragDrop<string[]>) {
    this.ss.drop(event);
  }

}

Test2 Component

<div class="container">
  <h2>Movies Watched</h2>
  <div cdkDropList [cdkDropListData]="MoviesWatched"
    [cdkDropListConnectedTo]="list-1" class="movie-list" (cdkDropListDropped)="onDrop($event)">
    <div class="movie-block" *ngFor="let moviesWatched of MoviesWatched" cdkDrag>{{moviesWatched}}</div>
  </div>
</div>

import { Component, OnInit } from '@angular/core';
import { CdkDragDrop } from '@angular/cdk/drag-drop';
import { ShareService } from '../share.service';


@Component({
  selector: 'app-test2',
  templateUrl: './test2.component.html',
  styleUrls: ['./test2.component.css']
})
export class Test2Component implements OnInit {

  constructor(private ss: ShareService) { }

  MoviesWatched = [
   'Transformers'
  ];

  ngOnInit() {
  }

  onDrop(event: CdkDragDrop<string[]>) {
    this.ss.drop(event);
  }

}

ShareService

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


@Injectable()
export class ShareService {

  constructor() { }

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

}

Here is the working link

ideeps
  • 379
  • 4
  • 15
  • Hi man, and how would it be done to drag the columns, in the case of "MOVIES WATCHED", "MOVIE"? https://stackoverflow.com/questions/72437853/angular-cdk-drag-with-two-lists?noredirect=1#comment127968880_72437853 – Rod May 31 '22 at 14:14
2

Component1

<div cdkDropList id="list-1" cdkDropListConnectedTo="list-2" (cdkDropListDropped)="drop($event)">
    <div *ngFor="let item of list" cdkDrag>{{ item }}</div>
</div>

Component 2

<div cdkDropList id="list-2" cdkDropListConnectedTo="list-1" (cdkDropListDropped)="drop($event)">
  <div *ngFor="let item of list" cdkDrag>{{ item }}</div>
</div>

shared Service for both component

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

Parent Component

<div cdkDropListGroup>
<component1></component1>
<component2></component2>
</div>

call drop method from both the component

drop(event: CdkDragDrop<string[]>) {
      this.sharedService.drop(event);
  }
0

To connect with the multiple list then use the blow code in drag and drop

[cdkDropListConnectedTo]="['element-1', 'element-2', 'element-3', 'element-4']"
Sumant Singh
  • 904
  • 1
  • 14
  • 16