How to use Angular7 (angular material) drag drop between two components
Asked Answered
A

5

38

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.

Alert answered 21/11, 2018 at 13:31 Comment(0)
C
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.

Cultivator answered 22/11, 2018 at 1:15 Comment(8)
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 thatAlert
@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.Cultivator
Sure. You are rock. I missed single quote for each id.Alert
in angular 7.2.1 i had to use [] around cdkDropListConnectedTo to work even with one list. [cdkDropListConnectedTo]="[list-1]" or [cdkDropListConnectedTo]="['list-1']"Extractor
@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"Cultivator
@Cultivator sorry, you're right. Tested right now and it works. don't know what was the mistake yesterday.Extractor
You saved my life sir. The Angular examples do not include the id=""-part, which was missing for me.Coruscate
Hi man, and how would it be done to drag the columns, in the case of "MOVIES WATCHED", "MOVIE"? #72438353Skeptical
S
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>
Swithbert answered 20/3, 2019 at 12:33 Comment(2)
What is your implementation, can you provide sample cause I am facing this problem now and without connectedTo it does'nt work. I have component with list where drag-drop is implemented and I want to use it in such group.Point
Saved the day!!Apothegm
H
11

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

Hutchens answered 10/6, 2020 at 21:5 Comment(1)
Hi man, and how would it be done to drag the columns, in the case of "MOVIES WATCHED", "MOVIE"? #72438353Skeptical
C
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);
  }
Christianity answered 22/8, 2019 at 9:59 Comment(0)
S
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']"
Snapper answered 18/11, 2020 at 6:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.