How to create drag and drop accordion list in Angular

·

3 min read

Play this article

In this article, I’d like to share with you how to create a list of accordion items, which also supports the drag and drop functionality.

We will build two lists, the first is the list of unassigned tasks, and the second is the list of assigned tasks. Users can drag each task and reorder it within the list, or move it from one list to another list.

The end result of this tutorial is as follows.

drag-and-drop.gif

So let’s get started…

First we need to import two modules DragDropModule and MatExpansionModule from Angular material.

import { DragDropModule } from '@angular/cdk/drag-drop';
import { MatExpansionModule } from '@angular/material';

To build the accordion list, we need some mock data to display. In the component class, we declare two lists of data, the first is unassignedTasks and the second is assignedTasks.

export class AppComponent {
  unassignedTasks: Task[] = [
    {
      id: '1',
      title: 'Task 1',
      description: 'This is task 1'
    },
    {
      id: '2',
      title: 'Task 2',
      description: 'This is task 2'
    },
    {
      id: '3',
      title: 'Task 3',
      description: 'This is task 3'
    }
  ];

  assignedTasks: Task[] = [
    {
      id: '4',
      title: 'Task 4',
      description: 'This is task 4'
    },
    {
      id: '5',
      title: 'Task 5',
      description: 'This is task 5'
    },
    {
      id: '6',
      title: 'Task 6',
      description: 'This is task 6'
    }
  ];
}

In order to make the task list data type-safe, we define an interface for it, for the sake of simplicity, it will contain only the id, title, and description.

export interface Task {
  id: string;
  title: string;
  description: string;
}

Next, we will use the mat-accordion and mat-expansion-panel of Angular material to create a list of accordion panels for unassigned tasks. We do the same for assigned tasks list.

<mat-accordion>
    <mat-expansion-panel *ngFor="let task of unassignedTasks">
      <mat-expansion-panel-header>
        <mat-panel-title>
          {{ task.title }}
        </mat-panel-title>
        <mat-panel-description>
          {{ task.description }}
        </mat-panel-description>
      </mat-expansion-panel-header>
      <p>This is the primary content of the panel.</p>
    </mat-expansion-panel>
</mat-accordion>

So now we have two lists of accordion items.

Next, we will add the drag and drop functionality for every list by adding the cdkDropList directive to mat-accordion component, and cdkDrag to mat-expansion-panel component.

<mat-accordion
  cdkDropList
  #unassignedList="cdkDropList"
  [cdkDropListData]="unassignedTasks"
  [cdkDropListConnectedTo]="[assignedList]"
  (cdkDropListDropped)="drop($event)"
>
    <mat-expansion-panel
      cdkDrag
      *ngFor="let task of unassignedTasks"
    >
      <mat-expansion-panel-header>
        <mat-panel-title>
          {{ task.title }}
        </mat-panel-title>
        <mat-panel-description>
          {{ task.description }}
        </mat-panel-description>
      </mat-expansion-panel-header>
      <p>This is the primary content of the panel.</p>
    </mat-expansion-panel>
</mat-accordion>

Here, we add the line [cdkDropListConnectTo]="[assignedList]" to allow the user to drag an item from this list and drop it to the assigned task list.

The drop method will look like this.

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

drop(event: CdkDragDrop<Task[]>) {
    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
      );
    }
  }

The code in if block handles the case when user moves items around its container, we will move it in the correct position. The code in else block handles the case when use drags an item from one list to another list, we call transferArrayItem to do that.

The moveItemInArray and transferArrayItem methods are imported from @angular/cdk/drag-drop package.

Conclusion

In this article, I showed you how to built two lists of accordion panel, which also have the drag and drop functionality supported.

You can find the full example code at the link here.

Thanks for reading and have a great day!