How to create drag and drop accordion list in Angular
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.
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!