angulardrag-and-dropangular-cdk

Drag and drop between lists that are in seperate components - Angular


I am trying to link to cdk drop lists so that they will be able to exchange items in their lists. This is my setup :

app.component.ts :

<app-ezei></app-ezei>
<app-skurt></app-skurt>

These are my 2 components :

1/ Ezei .ts:

import { Component, Input } from '@angular/core';
import { All } from '../all.interface';
import { CdkDragDrop, DragDropModule, moveItemInArray, transferArrayItem } from '@angular/cdk/drag-drop';
import { CommonModule } from '@angular/common';

@Component({
  selector: 'app-ezei',
  standalone: true,
  imports: [CommonModule, DragDropModule],
  templateUrl: './ezei.component.html',
  styleUrl: './ezei.component.css'
})
export class EzeiComponent {
  @Input() connectedList!:string;

  all: All[] = [
    { id: 2, teletubies: ['rouge', 'jaune', 'vert', 'violet'] },
    { id: 3, teletubies: ['bleu', 'orange', 'rose', 'gris'] },
    { id: 4, teletubies: ['noir', 'blanc', 'marron', 'cyan'] }
  ];
  
  even = [
    { id: 10, teletubies: [] }, 
    { id: 11, teletubies: [] }, 
    { id: 12, teletubies: [] }
  ];

  dropTeletubies(event: CdkDragDrop<string[]>) {
    console.log('triggered');
    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
      );
    }
  }
}

Ezei.html :

<div class="example-container">
    <h2>Even numbers</h2>
    <div>
      <div
        class="example-box"
        *ngFor="let number of all">
        <div>{{number.id}}</div>
        <div
          cdkDropList
          id="even"
          cdkDropListConnectedTo="all"
          [cdkDropListData]="number.teletubies"
          class="example-list teletubies-list"
          (cdkDropListDropped)="dropTeletubies($event)">
          <div
            *ngFor="let tele of number.teletubies"
            cdkDrag
            [cdkDragData]="tele"
            class="example-box">{{tele}}</div>
        </div>
      </div>
    </div>
  </div>

Skurt .ts :

import { CdkDragDrop, DragDropModule, moveItemInArray, transferArrayItem } from '@angular/cdk/drag-drop';
import { CommonModule } from '@angular/common';
import { Component, Input } from '@angular/core';

@Component({
  selector: 'app-skurt',
  standalone: true,
  imports: [CommonModule, DragDropModule],
  templateUrl: './skurt.component.html',
  styleUrl: './skurt.component.css'
})
export class SkurtComponent {
  @Input() connectedList!:string;
  teletubies = ['rouge', 'jaune', 'vert', 'violet'];

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

Skurt .html :

<div class="example-container">
    <h2>Available numbers</h2>
    <div
      id="all"
      cdkDropList
      cdkDropListConnectedTo="even"
      [cdkDropListData]="teletubies">
      <div
        class="example-box"
        *ngFor="let number of teletubies"
        [cdkDragData]="number"
        cdkDrag>{{number}}</div>
    </div>
 </div>

It is a very simple application, you can run it locally.

I tried linking them with ViewChildren but unfortunately it did not work.

What is the components are in an angular material cdk accordion like so :

<mat-accordion>
  <mat-expansion-panel [expanded]="openForLater" (closed)="closePanel('for-later')"
    (mouseenter)="isDragging && onPanelMouseEnter('for-later')">
    <mat-expansion-panel-header>
      <mat-panel-title>
        Pour plus tard
      </mat-panel-title>
      <mat-panel-description>
        Messages ajoutés lors de cette session
      </mat-panel-description>
    </mat-expansion-panel-header>    
    <app-ezei connectedList="even"></app-ezei>
    </mat-expansion-panel>

  <mat-expansion-panel [expanded]="openPreBroadcast" (closed)="closePanel('pre-broadcast')"
    (mouseenter)="isDragging && onPanelMouseEnter('pre-broadcast')">
    <mat-expansion-panel-header>
      <mat-panel-title>
        Liste de pré-diffusion
      </mat-panel-title>
    </mat-expansion-panel-header>
    <app-skurt connectedList="all"></app-skurt>
  </mat-expansion-panel>
</mat-accordion>

Solution

  • just enclosed between a cdkDropListGroup

    <div cdkDropListGroup>
       <app-ezei></app-ezei>
       <app-skurt></app-skurt>
    </div>
    

    A stackblitz. (see that it's the same example of "Drag&Drop connected sorting group", but using two separates components)